将带有循环引用的数据传递给 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 间接访问对象的代码