web-dev-qa-db-ja.com

Chrome `run_at`に設定された拡張機能` document_start`の実行が速すぎますか?

編集:私のChromeブラウザに問題があり、スクリプトとの競合が発生したため、完全な再インストールにより、問題の原因が何であっても排除されました。原因を突き止めた場合、それを含めます。ここに。

EDIT2:2017年にこれを読んでいる人に、私がこれを忘れていないことと、前回の編集以降、この問題が発生したことがないことを知らせたいだけです。

EDIT3:それは2019年であり、今のところ私はこの問題を二度と経験していません。


私は単純なChrome userscriptポートである拡張機能を作成する方法を学習しています。このスクリプトは、run atdocument-startに設定してTampermonkeyで完全に動作します最初からキャッチする必要があるイベントはすべてキャプチャされます。

ただし、Chrome拡張機能で同じ設定を設定すると、同じ実行設定がTampermonkeyの設定よりも速いため、最初の関数が失敗する原因となることがわかりました:(Uncaught TypeError: Cannot call method 'appendChild' of null.) 0.010秒後まで存在しないheadセクションにスクリプト要素を追加します。

これまでの私の汚い解決策は、タイマーを10に設定してsetInterval関数を使用してdocument.headが存在するかどうかを確認し、条件がtrueの場合にコードを続行することでした。

setIntervalに頼らずに、またはWebページのコンテキストでユーザースクリプトを実行しているように見えるTampermonkeyのgrant noneオプションを複製せずに、これを正しく動作させる方法はありますか?

以下は私のmanifest.jsonファイルです。

{
    "manifest_version": 2,
    "content_scripts": [ {
        "js":        [ "simpleuserscript.user.js" ],
        "matches":   [ "https://www.google.com/*"],
        "run_at":    "document_start"
    } ],
    "converted_from_user_script": true,
    "description":  "Chrome extension",
    "name":         "Testing",
    "version":      "1"
}

Chrome=がafterscriptexecuteイベントを採用する場合、これはすべて回避できますが、それが発生するまではloadイベントに行き詰まります。事前に感謝します提供されるヘルプ。


編集:私はすでに返信の提案を試しました:異なるrun atポイントを使用し、DOMContentLoadedを使用してdocument.documentElementに追加します。 1と2はスクリプトが初期のイベントを見逃す原因となり、3はdocument.headに追加しようとしたときと同じTypeErrorを返します。

document.readyState = loadingの場合、スクリプトを挿入/実行する必要があります。そうしないと、早い段階で必要なイベントを見逃してしまいますが、documentElementまたはheadのいずれかに子を追加できないほどには早い

simpleuserscript.user.js内のコードの例:

var script = document.createElement("script");
script.textContent = "console.log('success')";
if(document.head) {
    document.head.appendChild(script);
} else if(document.documentElement) {
    document.documentElement.appendChild(script);
}

コンソールにTypeError: Cannot call method 'appendChild' of nullが表示されます

14
Shadow

manifest.jsonで実行されるChrome拡張機能コンテンツスクリプトdocument_startから実行)、doの前に起動 document.readyStateドクinteractiveに達しました-これは、ほとんどのページ要素をいじり始めたい最も早い時期です。

ただし、必要に応じて、ほとんどの<script>ノードをすぐに挿入できます。まだ存在しないため、document.headdocument.bodyには当てはまりません。
代わりにdocumentElementに追加します。例えば:

var s = document.createElement ("script");
s.src = "http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js";
s.async = false;
document.documentElement.appendChild (s);

または

var s = document.createElement ("script");
s.src = chrome.extension.getURL ("MyPwnCode.js");
s.async = false;
document.documentElement.appendChild (s);

otherDOM要素を追加または変更する場合は、document_startで実行されているスクリプトで、DOMContentLoadedイベントのように待機します。そう:

document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);

function fireContentLoadedEvent () {
    console.log ("DOMContentLoaded");
    // PUT YOUR CODE HERE.
    //document.body.textContent = "Changed this!";
}
22
Brock Adams

あなたの問題は、"run_at": "document_start"を使用するときに、DOM内に存在することが許可されている唯一の要素が<html>要素であることです。まだ作成されていない要素にアクセスするなど、ページの読み込みに関連するエラーを回避するには、次のいずれかを行う必要があります。

  • スクリプトを"document_idle"または"document_end"で実行します。 "document_end"を使用しても、ページのすべての要素とリソースが完全に読み込まれたことは保証されません(ただし、DOMは既に解析されています)が、"document_idle"キーワードを使用すると、DOMスクリプトが実行される前に、すべての要素とリソースが解析され、適切に読み込まれています。

  • または、代わりに"document_start"と同様に、"DOMContentLoaded"リスナー内でコードをラップして"document_idle"を引き続き使用できます。これにより、DOMの読み込みと解析が完全に完了したときにコードが実行されます。次に例を示します。

    document.addEventListener("DOMContentLoaded", function() {
        // Run your code here...
    });
    
8
Marco Bonelli