将带有循环引用的数据传递给 Chrome 上的 javascript 网络工作者
Passing data with circular references to a javascript web worker on Chrome
我正在尝试将树的 html 渲染委托给网络工作者。树由节点组成,每个节点都有对下一个、上一个和父节点的引用。
表示树的数据是一个数组,包含所有的根节点。这个数组对 web worker 来说是 post,因为 web worker 的序列化程序应该支持循环引用。
节点少的时候,一切顺利。
使用Chrome浏览器,当节点数达到限制时,web worker 收不到任何东西;它的消息数据只是空的。控制台中没有出现错误。
Firefox、IE、Edge,一切正常。但我需要 Chrome 才能工作。
我试图简化我的代码并进行案例测试(参见下面的jsFiddle),看来问题出在对下一个节点的循环引用。
在这种情况下测试,100 个元素一切顺利,1000 个元素不起作用。
这个问题有什么解决办法吗?
更改我的代码以删除循环引用的唯一解决方案是什么?
HTML:
<p><button id='btn_100'>Test 100</button><button id='btn_1000'>Test 1000</button></p>
Javascript:
var workerCode = "self.onmessage = function(e) { self.postMessage(e.data ? 'ok ' + e.data.length : 'ko : null data'); };",
blob = new Blob([workerCode], {type: 'text/javascript'}),
blobUrl = URL.createObjectURL(blob),
worker = new Worker(blobUrl);
var btn_100 = document.getElementById('btn_100'),
btn_1000 = document.getElementById('btn_1000');
worker.onmessage = function(e) {
var log = document.createElement('p');
log.innerHTML = 'Response: <pre>' + e.data + '</pre>';
document.body.appendChild(log);
};
btn_100.onclick = function() { send(worker, 100); };
btn_1000.onclick = function() { send(worker, 1000); };
function send(w, n) {
var a = [];
for (var i = 0; i < n; i++) {
a.push({});
if (i > 0) a[i - 1].next = a[i];
}
w.postMessage(a);
}
Link 到 jsFiddle:https://jsfiddle.net/jvr4a50r/
实际上,浅拷贝发生在数组中对象的下一个 属性 中。所以为了去除循环引用,你必须在下一步属性中进行深拷贝。
您可以通过以下方式更新发送函数来删除循环引用。
var a = [];
for (var i = 0; i < n; i++) {
a.push({});
if (i > 0)
a[i - 1].next = JSON.parse(JSON.stringify(a[i]));
}
Google 已将此问题识别为错误:
https://bugs.chromium.org/p/chromium/issues/detail?id=825466
到目前为止,要确保没有问题,唯一的解决办法就是去掉对象中的循环引用。
在这种情况下,我遵循了以下步骤:
- 给每个节点一个唯一的id
- 通过将所有节点放在一个 "hasmap" 中来展平树,关键是唯一的 id
- 在节点中,用唯一id替换所有对其他节点的引用
- 当然还要更改所有使用引用通过 hashmap 间接访问对象的代码
我正在尝试将树的 html 渲染委托给网络工作者。树由节点组成,每个节点都有对下一个、上一个和父节点的引用。
表示树的数据是一个数组,包含所有的根节点。这个数组对 web worker 来说是 post,因为 web worker 的序列化程序应该支持循环引用。
节点少的时候,一切顺利。
使用Chrome浏览器,当节点数达到限制时,web worker 收不到任何东西;它的消息数据只是空的。控制台中没有出现错误。
Firefox、IE、Edge,一切正常。但我需要 Chrome 才能工作。
我试图简化我的代码并进行案例测试(参见下面的jsFiddle),看来问题出在对下一个节点的循环引用。 在这种情况下测试,100 个元素一切顺利,1000 个元素不起作用。
这个问题有什么解决办法吗? 更改我的代码以删除循环引用的唯一解决方案是什么?
HTML:
<p><button id='btn_100'>Test 100</button><button id='btn_1000'>Test 1000</button></p>
Javascript:
var workerCode = "self.onmessage = function(e) { self.postMessage(e.data ? 'ok ' + e.data.length : 'ko : null data'); };",
blob = new Blob([workerCode], {type: 'text/javascript'}),
blobUrl = URL.createObjectURL(blob),
worker = new Worker(blobUrl);
var btn_100 = document.getElementById('btn_100'),
btn_1000 = document.getElementById('btn_1000');
worker.onmessage = function(e) {
var log = document.createElement('p');
log.innerHTML = 'Response: <pre>' + e.data + '</pre>';
document.body.appendChild(log);
};
btn_100.onclick = function() { send(worker, 100); };
btn_1000.onclick = function() { send(worker, 1000); };
function send(w, n) {
var a = [];
for (var i = 0; i < n; i++) {
a.push({});
if (i > 0) a[i - 1].next = a[i];
}
w.postMessage(a);
}
Link 到 jsFiddle:https://jsfiddle.net/jvr4a50r/
实际上,浅拷贝发生在数组中对象的下一个 属性 中。所以为了去除循环引用,你必须在下一步属性中进行深拷贝。 您可以通过以下方式更新发送函数来删除循环引用。
var a = [];
for (var i = 0; i < n; i++) {
a.push({});
if (i > 0)
a[i - 1].next = JSON.parse(JSON.stringify(a[i]));
}
Google 已将此问题识别为错误: https://bugs.chromium.org/p/chromium/issues/detail?id=825466
到目前为止,要确保没有问题,唯一的解决办法就是去掉对象中的循环引用。
在这种情况下,我遵循了以下步骤:
- 给每个节点一个唯一的id
- 通过将所有节点放在一个 "hasmap" 中来展平树,关键是唯一的 id
- 在节点中,用唯一id替换所有对其他节点的引用
- 当然还要更改所有使用引用通过 hashmap 间接访问对象的代码