如何有效地将 Web Worker 中生成的大型数据集(可能超过一百万个项目)传输到 Vue.js 应用程序的主线程中,我面临着挑战。目前,当我尝试将生成的网格从工作线程传递到主线程时,会导致诸如“超出最大调用堆栈大小”之类的错误,甚至导致页面崩溃。
这是我当前的 Web Worker 代码的简化版本:
// gridWorker.js
self.onmessage = function (e) {
const { isUpdateColor, row, col, cellSize } = e.data;
if (isUpdateColor) {
const grid = Array.from({ length: row }, (_, i) => {
return Array.from({ length: col }, (_, j) => {
return {
i,
j,
code: `spot_${i}_${j}`,
// ... other properties
};
});
});
self.postMessage({ grid });
}
};
//main thread
<v-stage>
<v-layer ref="pathFinderLayer">
<div v-if="showTravelDistancePage">
<template v-for="rows in grid">
<v-rect v-for="(item, index) in rows" :key="item.code + '-' + index" :config="item"
@click="gridClick(item)" />
</template>
</div>
</v-layer>
</v-stage>
methods:
prepareGrid(isUpdateColor,cleanPath=true) {
this.gridWorker = new GridWorker();
this.gridWorker.onmessage = (event) => {
const { grid } = event.data;
this.grid = grid;
}
};
}
我怀疑问题是由于尝试将如此大的数据集传递到主线程而引起的。有没有更有效的方法来处理这种情况?即使我逐块传递部分数据,如果网格对象太多,它仍然会使我的页面崩溃。
方法一:在主线程上生成
最初,我尝试直接在主线程上生成大网格。然而,由于对象数量巨大,这种方法会导致页面崩溃。
方法 2:在 Web Worker 中生成并传递整个网格
为了解决性能问题,我将网格生成过程移至 Web Worker。虽然这成功地将生成卸载到单独的线程,但将整个生成的网格传递回主线程仍然会导致页面崩溃。
方法 3:通过 Chunk 在 Web Worker Chunk 中生成
在最近的尝试中,我选择在 Web Worker 中分块生成网格。然后,我将每个块单独传递到主线程,将块存储在主网格内。不幸的是,这个策略在某个时候也导致了崩溃。
似乎是 XY 问题。简短的回答 - 您不应该做诸如生成一百万项 UI 数据之类的事情。 您应该只生成屏幕上可见的数据,这称为虚拟滚动。 因此,您可以在需要时动态生成数据。
如果您仍需要提前生成 100 万个项目,请在工作线程中执行此操作,并仅在滚动时传输可见数据。
一个带有简单虚拟列表的示例(它甚至可以更好地滚动)。正如你所看到的,我动态生成 HTML(更高级的滚动也会偏移顶部项目,模仿项目内的滚动):
const arr = Array.from({length:1000000}, () => Math.random());
unorderedList.style.height = (arr.length * 32) + 'px';
drawItems();
wrapper.addEventListener('scroll', drawItems);
function drawItems(){
const pos = wrapper.scrollTop;
const from = pos / 32 | 0;
const to = from + wrapper.offsetHeight / 32 | 0 + 1;
unorderedList.innerHTML = arr.slice(from, to).map((item, idx) => `<li>${from + idx + 1}: ${item}</li>`).join('');
let top = -32;
[...unorderedList.children].forEach((li, idx) => li.style.top = `${top += 32}px`);
}
#wrapper{
max-height:100vh;
overflow:auto;
}
body{
margin:0;
padding:0;
overflow:hidden;
}
li{
position:absolute;
height:32px;
line-hieght:32px;
}
<div id="wrapper">
<ul id="unorderedList"></ul>
</div>