上篇文章
web worker涉及到postMessage,在web worker 中可以进行数据传输。更高级用法可以转移对象,并表示很好奇,觉得以后应该会有用,所以打算深入了解下。
1、重点转移对象参数transfer定义
worker.postMessage(message)
worker.postMessage(message, transfer)
- 其中
message可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送,但是一旦二级制数据量太大,会导致性能问题。 transfer可转移对象是如ArrayBuffer,MessagePort或ImageBitmap等二进制数据。JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。
2、案例
单个参数使用,输出结果如下:
<script type="text/plain" id="workerJS">
self.addEventListener('message', function(event) {
var ab = event.data;
postMessage('worker线程: ab.byteLength = ' + ab.byteLength);
});
</script>
<script>
let workerJS = document.getElementById('workerJS').innerText;
let blob = new Blob([workerJS]);
let blobURL = window.URL.createObjectURL(blob);
const worker = new Worker(blobURL);
var ab = new ArrayBuffer(1000000000);
for (var i = 0; i < ab.length; ++i) {
ab[i] = i * 2;
}
worker.postMessage(ab);
console.log("主线程 abbyteLength = ", ab.byteLength);
worker.addEventListener('message', function (event) {
console.log(event.data);
});
//主线程 ab.byteLength = 1000000000
//worker线程: ab.byteLength = 1000000000
</script>
两个参数使用,结果如下:
<script type="text/plain" id="workerJS">
self.addEventListener('message', function(event) {
var ab = event.data;
postMessage('worker线程: ab.byteLength = ' + ab.byteLength);
});
</script>
<script>
let workerJS = document.getElementById('workerJS').innerText;
let blob = new Blob([workerJS]);
let blobURL = window.URL.createObjectURL(blob);
const worker = new Worker(blobURL);
var ab = new ArrayBuffer(1000000000);
for (var i = 0; i < ab.length; ++i) {
ab[i] = i * 2;
}
worker.postMessage(ab,[ab]);
console.log("主线程 abbyteLength = ", ab.byteLength);
worker.addEventListener('message', function (event) {
console.log(event.data);
});
//主线程 ab.byteLength = 0
//worker线程: ab.byteLength = 1000000000
</script>
3、结论
经过简单的数据对比,发现了数据进行了转移了。 同时观察内存使用率,确实发现使用转移对象,对于内存使用率不会怎么增加。 而使用序列化的,随着数据量越来越多,内存使用情况就会越高了,同时需要把worker关闭了,内存才会明显下降。 说明没使用情况下,一直开着worker对于性能也是一种消耗。