本文详解在three.js中利用Web Worker解决JavaScript单线程阻塞问题。通过对比1000个Mesh在大量位置计算下的FPS表现,展示Web Worker如何保持主线程流畅。测试数据显示,即使计算量增加,使用Web Worker仍能将FPS稳定在60左右,显著提升CPU利用率与渲染性能。
前言
本文介绍Web Worker及其在three.js中的应用。JavaScript默认是单线程执行,这意味着运行JS代码时UI渲染会暂停,对于拥有多核CPU的电脑而言,这种单线程限制显得不够高效。Web Worker的出现部分解决了这一问题。根据官方定义,Web Worker允许脚本创建后台任务,任务执行期间可与创建者进行通信。创建Worker只需调用Worker(URL)构造函数,参数URL指向指定的脚本文件。更多关于Web Worker的知识可查阅相关文档。线性案例请参考web-worker链接。
1. 在three.js中使用多线程
在three.js中引入Web Worker通常是为了解决大量计算导致的CPU阻塞问题。例如,假设创建了1000个Mesh对象,

若仅让它们进行简单的运动,CPU压力很小,FPS可维持在60左右。但如果这1000个Mesh的位置需要通过大量计算得出,FPS会显著降低(与计算量呈负相关)。以下是一段示例代码:
for(let i=0; i<num; i++) {
let angle = positions[i].y / (1000 / (Math.PI * 10));
positions[i].x = positions[i].x + Math.sin(angle);
positions[i].z = positions[i].z + Math.cos(angle);
positions[i].y = positions[i].y + 1;
//上面就是简单的位置变化,下面的代码模拟复杂的变化,累加100000次(这是非常占用线程的情况)
for(let j=1, total=1; j<=100000; j++) {
total += j;
}
if(positions[i].y > 500) {
positions[i].y = positions[i].y - 1000;
}
}
for(var i=0; i<num; i++) {
group.children[i].position.set(positions[i].x, positions[i].y, positions[i].z);
}
positions数组存储了1000个Mesh的位置信息,group包含所有Mesh。每次渲染时更新positions数组,并将新值赋给Group中的每个Mesh。这种情况下,FPS可能低至7FPS,场景转动时能明显感到卡顿。接下来使用Web Worker解决此问题,主线程代码如下:
myWorker = new Worker('/static/js/worker.js');
myWorker.postMessage(positions);
myWorker.onmessage = e => {
let positions = e.data;
for(var i=0; i<num; i++) {
group.children[i].position.set(positions[i].x, positions[i].y, positions[i].z);
}
}
Worker脚本代码如下:
onmessage = function(e) {
let num = 1000;
let positions = e.data;
setInterval(e => {
for(let i=0; i<num; i++) {
let angle = positions[i].y / (1000 / (Math.PI * 10));
positions[i].x = positions[i].x + Math.sin(angle);
positions[i].z = positions[i].z + Math.cos(angle);
positions[i].y = positions[i].y + 1;
for(let j=1, total=1; j<=100000; j++) {
total += j;
}
if(positions[i].y > 500) {
positions[i].y = positions[i].y - 1000;
}
}
postMessage(positions);
}, 1000 / 60)
};
主要逻辑与未使用Web Worker时几乎相同,区别在于位置处理代码在新线程中执行。setInterval定时器每次完成位置计算后,通过postMessage(positions)将结果返回给主线程。主线程通过onmessage接收信息,返回对象的data属性即为新的positions数据。此时FPS可恢复至60左右,场景转动流畅,无明显卡顿。效果令人满意。
2. 性能分析
前文提到,每次位置计算中包含10万次累加操作。未使用Web Worker时,FPS降至7。以下是更多对比数据(数据仅供参考,实际表现与当前环境及配置有关)。
| 累加次数(万次) | 使用Web Worker | 未使用Web Worker |
|---|---|---|
| 1 | 60 | 60 |
| 3 | 60 | 39 |
| 5 | 60 | 26 |
| 7 | 60 | 11 |
| 9 | 60 | 8 |
| 11 | 60 | 6 |
从数据可以看出,无论计算量多大,使用Web Worker均不影响主线程,而未使用时影响严重。下面展示两种情况下的电脑性能对比:
(未使用Web Worker)

(使用Web Worker)

由此可见,使用更多线程能显著提升CPU利用率。读者可打开线上案例亲自测试。
总结
至此,关于three.js中多线程使用及性能测试的文章介绍完毕。更多相关three.js多线程使用及性能测试内容,请搜索本站以往文章或继续浏览下方相关文章,希望大家以后多多支持本站!
版权声明:本文为郭志强的原创文章,转载请附上原文出处链接及本声明。原文链接:https://www.mrguo.link