2

コンテンツスクリプトでは、開かれたすべてのポップアップウィンドウを追跡するのにMapを使用しています。次のようにMapにおけるキーと値のペアが構成されている:Chromeのコンテンツスクリプトでキーマップが奇妙に動作する

  • キー - 問題は、時々Map.prototype.has()Map.prototype.get()であるいくつかの関連データ

- Window.open()

  • 値によって返された参照予期しない結果を返す。

    // content.js 
    
    let map = new Map(); 
    let popup = window.open('https://www.google.com'); 
    let data = {}; 
    
    map.set(popup, data); 
    
    // retrieve data later 
    window.setTimeout(() => { 
    
        // should return true, but sometimes return false 
        console.log(map.has(popup)); 
    
        // should return {}, but sometimes return undefined 
        console.log(map.get(popup)); 
    
    }, 3000); 
    

    追加のキーと参照popupは常に何らかの理由で「等しい」と見なされていないようです。そして、このあいまいな状況はコンテンツスクリプトにのみ存在するように見えます。上記のコードがブラウザのコンソールで実行される場合は、map.has()map.get()となります。常にが正しい値を返します。

    私の質問は次のとおりです。なぜこれが起こったのですか?それは私が気づいていなかったコンテンツスクリプトの根底にあるメカニズムによって引き起こされたのでしょうか?

  • +1

    実際のコードはIIFEでラップされていますか、実際はグローバルスコープの変数ですか? 'popup'がページ上の何かによって再割り当てされる可能性はありますか? – loganfsmyth

    +0

    @loganfsmythデバッグ用にこの単純化されたバージョンを構築しました。だから私のコンテンツスクリプトには本当のコードがあります。 IIFEのラッピングはありません。他のコンテンツスクリプトはありません。また、エクステンションにはバックグラウンドスクリプトもありません。 – Microloft

    +0

    これはブラウザのバグかもしれませんが、 'const'を試してみてください。実際には、値を再割り当てしない場合に使用する必要があります。 – wOxxOm

    答えて

    2

    これは(Chrome 60.0.3112.78、Windows 10、64ビット)、reported it as a bugを再現できます。これを発見するのにうってつけ!

    バグが知らず知らずのうちクローム62.0.3175.2(カナリア)に固定し、私はまだ失敗WeakMap(https://jsfiddle.net/769a0qmu)を使用して、新しいデモを構築した:クローム62.0.3175.2(カナリア)出力で

    var map = new WeakMap(); 
    var popup = window.open("https://google.com"); // requires popups to be enabled 
    map.set(popup, "data"); 
    window.setTimeout(function() { 
        console.log(map.get(popup)); // expect: "data" 
        map.set(popup, "modified"); 
        console.log(map.get(popup)); // expect: "modified" 
    }, 3000); 
    

    をバグレポートから

    data 
    data 
    

    説明です

    Comment 10 by adamk

    V8の問題は、リモートコンテキストのために作成されたグローバルが%_ClassOf()の空の文字列を返しているようです。これにより、そのようなオブジェクトのハッシュコードを検索するときに、間違ったパスである が表示されます。

    Comment 12 by adamk

    ここでは、V8の内部で何が起こっているのです。最初に、元のスタックからのメモ オーバーフローレポートはこれがマップで壊れていたが、もはやそれではないことを報告します。 MapとWeakMapは、正確に同じロジックを使用してオブジェクトのハッシュ コードを取得するために使用されました。このコードは、(それが 内部V8のJSで書かれています)次のようになります。

    function GetExistingHash(key) { 
        if (IS_RECEIVER(key) && !IS_PROXY(key) && !IS_GLOBAL(key)) { 
        var hash = GET_PRIVATE(key, hashCodeSymbol); 
        return hash; 
        } 
        return %GenericHash(key); 
    } 
    

    注意IS_GLOBAL(key)。それは %_ClassOf(key) == 'global'に拡大されるマクロです。RemoteContextで作成されたグローバル オブジェクトは空の文字列を返すため、このチェックに失敗して間違っています グローバル固有のロジック(C++ ランタイムで処理される)ではなく、ハッシュコードを扱うために通常のオブジェクトメカニズムを使用しようとしています 機能%GenericHash()。数ヶ月の最後のカップル以上

    、V8は、彼らはもはやWeakMapで上記 ロジックを共有していることを意味していないこれ、JSのうち、 地図メソッドの実装を移動しました。具体的には、どのようにについての決定を のハッシュコードは常に%GenericHashに直接送られ、 異なるメカニズム(インスタンスタイプチェック)を参照して、 のハッシュコードを処理する方法を確認してください。このメソッドは、 RemoteContextのケースで正しい答えを得て、 JSGlobalProxy (source)、 の特殊なhashフィールドを意図したとおりに使用します。

    「WeakMapケースを修正するために何をすべきかという疑問があります。 v8の中で進行中の作業は、最終的には (マップの修正方法に似ています)になりますが、修正されるまではおそらく の順です。私たちが早急に修正したい場合は、 %_ClassOfが "global"を返すようにハックを試みることができますが、それはまだ明確ではありません どれくらいの仕事があるのでしょうか。

    これは2つの安定したリリースで既に破られていることを考えれば、私は で、それがv8側で修正されるのを待つことになります。私は を一時的に優先度を下げて、これをv8バグのブロックとしてマークしました。 しかし、それは価値があると思われる場合、より早く何かをすることにはオープンです。

    アップデート(2017年8月24日)

    固定としてバグがマークされています。

    関連する問題