web-dev-qa-db-ja.com

chrome.tabs.queryを呼び出した後、結果は利用できません

Google Chromeの拡張機能を作成(学習)しています。

一部のコードをデバッグするために、次のようにconsole.log()を挿入しました。

var fourmTabs = new Array();
chrome.tabs.query({}, function (tabs) {
    for (var i = 0; i < tabs.length; i++) {
        fourmTabs[i] = tabs[i];
    }
});
for (var i = 0; i < fourmTabs.length; i++) {
    if (fourmTabs[i] != null)
        window.console.log(fourmTabs[i].url);
    else {
        window.console.log("??" + i);
    }
}

これは非常に単純なコードです。すべてのタブ情報を独自の配列に取得し、いくつかのものを出力します。

コードが正常に機能するかどうかを確認するために、コードを実行します。ここに問題があります:

  • (開発者ツールを介して)ブレークポイントを使用すると、コードは正常に実行されます。
  • ブレークポイントがないと、何も出力されません。

理由は何ですか?

21
samy

問題は次のように単純化できます。

/*1.*/ var fourmTabs = [];
/*2.*/ chrome.tabs.query({}, function(tabs) {
/*3.*/     fourmTabs[0] = tabs[0];
/*4.*/ });
/*5.*/ console.log(fourmTabs[0]);

5行目に到達すると、fourmTabs配列が(3行目で)更新されることが期待されます。
それは間違ったです。なぜならchrome.tabs.queryメソッドは非同期です。


非同期の側面の重要性を理解してもらうために、コードと同じ構造のコードスニペットを示しますおよびストーリー。

/*1.*/ var rope = null;
/*2.*/ requestRope(function(receivedRope) {
/*3.*/     rope = receivedRope;
/*4.*/ });
/*5.*/ grab(rope);
  • 1行目で、ロープの存在がアナウンスされます。
  • 2〜4行目で、コールバック関数が作成されます。これは、requestRope関数によって呼び出される必要があります。
  • 5行目では、grab関数を使用してロープをつかみます。

requestRopeが実装されている場合同期的に、問題はありません:
あなた:「こんにちは、ロープが欲しいです。ロープを投げてください「コールバック関数を呼び出す」 持っているとき」
彼女:「もちろん」 ロープを投げる
あなた:ロープをジャンプしてつかむ-あなたはなんとか反対側に着くことができます、生きている

requestRopeが実装されている場合非同期、同期として扱うと問題が発生する可能性があります。
あなた:「私にロープを投げてください。」
彼女:「もちろん。見てみましょう...」
あなた:ジャンプしてロープをつかもうとしますロープがないので、倒れて死にます。
彼女:ロープを投げる もちろん、遅すぎます。


非同期実装関数と同期実装関数の違いを確認したので、元の質問を解決しましょう。

var fourmTabs = new Array();
chrome.tabs.query({}, function (tabs) {
    for (var i = 0; i < tabs.length; i++) {
        fourmTabs[i] = tabs[i];
    }
    // Moved code inside the callback handler
    for (var i = 0; i < fourmTabs.length; i++) {
        if (fourmTabs[i] != null)
           window.console.log(fourmTabs[i].url);
        else {
            window.console.log("??" + i);
        }
    }
});
// <moved code inside callback function of chrome.tabs.query>

ブレークポイントを使用すると、コードは機能します。これは、コードの2番目の部分に到達するまでに、コールバックがすでに呼び出されているためです。

91
Rob W