在我的内容脚本中,我使用Map
来跟踪所有打开的弹出窗口。 Map
中的键值对构造如下:
Window.open()
问题是,Map.prototype.has()
和Map.prototype.get()
有时会返回意外结果。
// 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()
将始终返回正确的值。
所以我的问题是:为什么会这样?它是由一些我不知道的内容脚本的基础机制引起的吗?
答案 0 :(得分:2)
我可以重现这一点(Chrome 60.0.3112.78,Windows 10,64位)和reported it as a bug。为发现这个做得好!
在Chrome 62.0.3175.2(金丝雀)中无意中修复了该错误,但是我使用WeakMap构建了一个仍然失败的新演示(https://jsfiddle.net/769a0qmu):
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);
在Chrome 62.0.3175.2(金丝雀)中,输出为
data
data
错误报告的说明
V8中的问题似乎是为远程上下文创建的全局变量 返回
%_ClassOf()
的空字符串。这导致我们走下坡路 查找此类对象的哈希码时的错误路径。这里是V8内部发生了什么。首先,请注意原始堆栈 溢出报告,这曾经在Map中被破坏,但不再是。 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已经推动了它的实施 从JS中映射方法,这意味着他们不再共享上述内容 WeakMap的逻辑。特别是关于如何找到的决定 哈希码总是直接转到
%GenericHash
,后者使用a 关键的不同机制(实例类型检查),看看如何 处理哈希码。这种方法得到了正确的答案 RemoteContext的情况,因此使用特殊的hash
字段 JSGlobalProxy (source), 如预期的那样。所有这些都说明了解决WeakMap案例该怎么做的问题。 V8内部正在进行的工作最终将使其消失 (类似于Map如何修复),但这可能是大约的顺序 几个星期,直到它被修复。如果我们想早点修复,我们可以尝试 黑客入侵%_ClassOf返回"全球",但还不清楚 对我来说有多少工作。
鉴于两个稳定版本已经被打破了,我还是 倾向于等待它固定在v8侧。我'已经 暂时降低优先级并将其标记为阻止v8错误, 但是,如果看起来值得的话,我愿意尽早做点什么。
更新(2017-08-24):
该错误已被标记为已修复。