【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(二)

Web Worker

背景

众所周知,JavaScript是单线程模型,所有的任务只能在同一条线程上进行完成,前边的任务未完成则后续任务只能等待,所以在H中引入了Web Worker,为JavaScript创建一个多线程的环境,将部分任务提供给它在后台运行,前台后台同时运行。

Web Worker是后台运行的JavaScript,它独立于其他脚本且不会影响页面的性能。引入Web Worker的好处是一些计算密集型或高延迟的任务,被 Web Worker 线程所处理,主线程就会很流畅,不会被阻塞或拖慢,而此时 Web Worker 在后台运行。但是这也正是 Web Worker 比较耗费资源的原因。

浏览器支持及使用

除了IE外所有主流浏览器均支持Web Worker。

可在创建Worker之前检测是否支持

1
2
3
4
5
6
if(typeof(Worker)!=="undefined") {
// 支持.....
}
else {
// 不支持..
}

Web Worker在一个独立的线程中运行,所以代码需要放在一个单独的文件中。加载时如果存在指定文件,浏览器会在文件下载完毕后执行,生成新的Worker线程,如果加载文件失败不会有任何提示。

创建Worker后利用postMessage()启动

1
2
3
var worker = new Worker('worker.js');
var info = 'start worker!'
worker.postMessage(info);

在Worker中使用onmessge事件接收主线程的消息来实现一些操作。

1
2
3
onmessage = function(e) {
var data = e.data
}

同样的,从Worker发消息到主线程也采用同样方法。

1
2
3
4
5
6
// Receive the message from the main thread
onmessage = function(e) {
var info = e.data;
var result = info + ' get';
postMessage(result);
};

可以使用addEventListener来替换onmessage

停止Worker有两种方法,在主线程中调用worker.terminate()或在内部调用self.close()均可。在任务结束后一定要停止,因为Worker会一直在后台运行耗费资源,不应该过度使用。

注意事项

  • 主线程与Worker之间传递的消息不是共享的,因为系统将消息对象传递给Worker后会将其序列化,在另一端再取消序列化。大部分浏览器通过JSON的编码解码实现。
  • Worker的self和this都是Worker的全局作用域。
  • Worker无法处理DOM,无法使用window对象、document对象等。
  • Worker可以生成子Worker,但需要注意:子Worker必须和父线程处在相同origin中,其中的URI应相对于父Worker位置解析。

Cesium的异步+多线程

Cesium中涉及到大量三维球计算和大数据量交互,比如三角网,参数化Geometry等,都是在Worker中实现的,参数的传递以及不同类型对应的不同算法。

Cesium源码中Source\Core\TaskProcessor.js内为Cesium封装的Worker。我们简单来看一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function TaskProcessor(workerPath, maximumActiveTasks) {
this._workerPath = new Uri(workerPath).isAbsolute()
? workerPath
: TaskProcessor._workerModulePrefix + workerPath;
this._maximumActiveTasks = defaultValue(
maximumActiveTasks,
Number.POSITIVE_INFINITY
);
this._activeTasks = 0;
this._deferreds = {};
this._nextID = 0;
}


TaskProcessor.prototype.scheduleTask = function (
parameters,
transferableObjects
) {
if (!defined(this._worker)) {
this._worker = createWorker(this);
}

// ……


return when(canTransferArrayBuffer(), function (canTransferArrayBuffer) {
// ……

return deferred.promise;
});
};

我们使用时只需要创建一个TaskProcessor,指定类型,然后调用scheduleTask,接收对应具体参数,然后返回一个Promise对象,我们可以异步的获取的对应结果。

使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
var taskProcessor = new Cesium.TaskProcessor('myWorkerPath');
var promise = taskProcessor.scheduleTask({
someParameter : true,
another : 'hello'
});
if (!Cesium.defined(promise)) {
// too many active tasks - try again later
} else {
Cesium.when(promise, function(result) {
// use the result of the task
});
}

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(二)
https://moewang0321.github.io/2021/06/21/Cesium是如何实现多线程的/
作者
Moe Wang
发布于
2021年6月21日
许可协议