1. 引言
浏览器是多进程的,每打开一个网页,都会开启一个渲染进程,渲染进程包含:
- GUI渲染线程 (有且只有一个
- JS引擎线程 (有且只有一个
- 事件触发线程
- 定时器触发线程
- 异步http请求线程
GUI渲染线程与JS引擎线程是互斥的,且JS引擎线程会先执行,如果JS代码卡住会导致GUI绘制卡住
- 浏览器的进程与线程--深入同步、异步问题 - 知乎 (zhihu.com
- Web Worker 之全面讲解 - 知乎 (zhihu.com
Web Workers就是创建JS代码执行的线程,使得JS代码执行能以多线程的方式执行,避免JS引擎线程卡住
Web Workers的解释可以参考:
- Web Workers API - Web API 接口参考 | MDN (mozilla.org
- Web Worker 使用教程 - 阮一峰的网络日志 (ruanyifeng.com
2. Web Workers
通常而言,Web Workers包含:
- 专用线程(Dedicated Workers)
- 共享线程(Shared Workers)
- 后台线程(Service Workers)等
Web Worker的大致的使用方法如下:
创建一个Web Worker:
const worker = new Worker('WebWorkerTest.js'
- 加载Web Worker执行的JS代码文件需要使用HTTP或HTTPS协议,即,需要搭建网络服务器
WebWorkerTest.js
是Web Worker执行的JS代码文件
(在主线程里)向创建的Web Worker发送数据:
worker.postMessage([2, 3]
(在子线程Web Worker,即WebWorkerTest.js
中)接收主线程的数据、处理并发送给主线程:
onmessage = function(e {
console.log('Message received from main script'
const workerResult = e.data[0] * e.data[1]
console.log('Posting message back to main script'
postMessage(workerResult
}
(在主线程里)接收Web Worker发送的数据:
worker.onmessage = (e => {
console.log("Result:", e.data
}
综上,此处创建了两个文件:WebWorkerTest.js和WebWorkerTest.html
WebWorkerTest.html代码如下:
<body>
<script>
const worker = new Worker('WebWorkerTest.js'
worker.postMessage([2, 3]
worker.onmessage = (e => {
console.log("Result:", e.data
}
</script>
</body>
WebWorkerTest.js代码如下:
onmessage = function(e {
console.log('Message received from main script'
const workerResult = e.data[0] * e.data[1]
console.log('Posting message back to main script'
postMessage(workerResult
}
运行结果如下(使用VS Code和Live Server插件):
- Web Workers API - Web API 接口参考 | MDN (mozilla.org
- Web Worker 使用教程 - 阮一峰的网络日志 (ruanyifeng.com
3. Cesium中的Web Workers
Cesium源码中,对Web Workers进行了封装,封装为TaskProcessor
TaskProcessor使用示例为:
const taskProcessor = new Cesium.TaskProcessor('myWorkerPath';
const promise = taskProcessor.scheduleTask({
someParameter : true,
another : 'hello'
};
if (!Cesium.defined(promise {
// too many active tasks - try again later
} else {
promise.then(function(result {
// use the result of the task
};
}
查看源码,可以知道taskProcessor.scheduleTask(
函数为:
TaskProcessor.prototype.scheduleTask = function (parameters, transferableObjects {
// ...
this._worker = createWorker(this;
return Promise.resolve(canTransferArrayBuffer(.then(function (
canTransferArrayBuffer
{
processor._worker.postMessage(
{
id: id,
parameters: parameters,
canTransferArrayBuffer: canTransferArrayBuffer,
},
transferableObjects
;
return deferred.promise;
};
};
createWorker(
函数为function createWorker(processor { const worker = new Worker(getBootstrapperUrl(; worker.postMessage = defaultValue( worker.webkitPostMessage, worker.postMessage ; // ... return worker; }
不难看出,Cesium中将Web Workers封装成了
Promise
,既有操作Promise
的优雅,又有调用Web Workers
带来的多线程优势Scene\Primitive.js中,使用TaskProcessor创建
Geometry
:createGeometry.js的文件名创建TaskProcessor:
if (!defined(createGeometryTaskProcessors { createGeometryTaskProcessors = new Array(numberOfCreationWorkers; for (i = 0; i < numberOfCreationWorkers; i++ { createGeometryTaskProcessors[i] = new TaskProcessor("createGeometry"; } }
然后创建promise数组:
promises.push( createGeometryTaskProcessors[i].scheduleTask( { subTasks: subTasks[i], }, subTaskTransferableObjects ;
最后使用
Promise.all
方法执行所有任务并等待结果返回:Promise.all(promises .then(function (results { primitive._createGeometryResults = results; primitive._state = PrimitiveState.CREATED; } .catch(function (error { setReady(primitive, frameState, PrimitiveState.FAILED, error; };
4. 参考资料
[1] Web Workers API - Web API 接口参考 | MDN (mozilla.org
[3] Cesium原理篇:4Web Workers剖析 - fu*k - 博客园 (cnblogs.com
[5] Web Worker 之全面讲解 - 知乎 (zhihu.com
[6] 使用 Service Worker - Web API 接口参考 | MDN (mozilla.org