特定のアプローチの方が優れているとコメントで主張する代わりに、より建設的になり、私が共同で作成した特定の実装を示して回答を追加し、遭遇する可能性のある落とし穴を説明します。コード スニペットは Twitter とは異なるサービスを参照していますが、目的は同じです。実際、このコードの目的は未読メッセージの正確な数を報告することなので、あなたのコードはもっと単純かもしれません。
私のアプローチはSO に関する回答に基づいており、ポーリング駆動型(一定間隔で状態をチェックする)ではなく、イベント駆動型(状態の潜在的な変化が通知される) です。
利点には、変更の即時検出 (そうでなければ次のポーリングまで検出されない) と、条件が変更されていない間、ポーリングでリソースを浪費しないことが含まれます。確かに、2 番目の議論はここではほとんど当てはまりませんが、最初の議論は依然として有効です。
アーキテクチャの概要:
問題のページにコンテンツ スクリプトを挿入します。
タイトルの初期状態を分析し、 を介してバックグラウンド ページにレポートしますsendMessage
。
タイトル変更イベントのハンドラを登録します。
イベントが発生してハンドラーが呼び出されるたびに、タイトルの新しい状態を分析し、 を介してバックグラウンド ページに報告しますsendMessage
。
すでにステップ 1 には落とし穴があります。通常のコンテンツ スクリプト インジェクション メカニズムは、コンテンツ スクリプトがマニフェストで定義されている場合、URL に一致するページへのナビゲーション時にページに挿入します。
"content_scripts": [
{
"matches": [
"*://theoldreader.com/*"
],
"js": ["observer.js"],
"run_at": "document_idle"
}
]
拡張機能がリロードされるまで、これはかなりうまく機能します。これは、行った変更を適用している開発中、または自動更新されているデプロイされたインスタンスで発生する可能性があります。その場合、コンテンツ スクリプトは既存の開いているページに再挿入されません(リロードなどのナビゲーションが発生するまで)。したがって、マニフェスト ベースのインジェクションに依存している場合は、拡張機能の初期化時に既に開いているタブへのプログラムによるインジェクションを含めることも検討する必要があります。
function startupInject() {
chrome.tabs.query(
{url: "*://theoldreader.com/*"},
function (tabs) {
for (var i in tabs) {
chrome.tabs.executeScript(tabs[i].id, {file: "observer.js"});
}
}
);
}
一方、拡張機能のリロード時にアクティブだったコンテンツ スクリプト インスタンスは終了せず、孤立します。すべてのsendMessage
リクエストまたは同様のリクエストは失敗します。したがって、親拡張機能と通信しようとするときは常に例外をチェックし、失敗した場合は (ハンドラーを削除して) 自己終了することをお勧めします。
try {
chrome.runtime.sendMessage({'count' : count});
} catch(e) { // Happens when parent extension is no longer available or was reloaded
console.warn("Could not communicate with parent extension, deregistering observer");
observer.disconnect();
}
ステップ 2 にも落とし穴がありますが、視聴しているサービスの詳細によって異なります。コンテンツ スクリプトの範囲内の一部のページでは、未読アイテムの数が表示されませんが、新しいメッセージがないという意味ではありません。
Web サービスがどのように機能するかを観察した結果、タイトルがナビゲーションのないものに変更された場合、正しい場合は新しい値を想定しても安全ですが、最初のタイトルの「新しいアイテムはありません」は信頼できないとして無視する必要があるという結論に達しました。
したがって、分析コードは、それが最初の読み取りであるか、更新の処理であるかを説明します。
function notify(title, changed) {
// ...
var match = /^\((\d+)\)/.exec(title);
var match_zero = /^The Old Reader$/.exec(title);
if (match && match[1]) {
count = match[1];
} else if (match_zero && changed) {
count = 0;
}
// else, consider that we don't know the count
//...
}
手順 2で、最初のタイトルとchanged
=で呼び出されます。false
ステップ 3 と 4 は、「タイトルの変更を監視する方法」(イベント駆動型の方法) に対する主な答えです。
var target = document.querySelector('head > title');
var observer = new window.MutationObserver(
function(mutations) {
mutations.forEach(
function(mutation){
notify(mutation.target.textContent, true);
}
);
}
);
observer.observe(target, { subtree: true, characterData: true, childList: true });
特定のオプションobserver.observe
が設定されている理由の詳細については、元の回答を参照してください。
は=でnotify
呼び出されるため、ナビゲーションなしで「(1) The Old Reader」から「The Old Reader」に移動すると、未読メッセージがゼロになる「真の」変更と見なされることに注意してください。changed
true