Web Worker串行加载优化

问题:worker的串行加载问题

最近在开发wasm播放器,流媒体解析、音视频编解码都是重CPU的操作,如果在主线程完成,有可能会导致性能不佳。因此,打算采用worker来降低主线程的负担。

这个时候会遇到个问题,如果采用类似new Worker(workerFilePath) 的方式来初始化worker,会出现主文件、worker文件串行加载的问题。

做了个简单demo,github完整示例可点击这里

// main.js
const worker = new Worker('worker.js');

worker.addEventListener('message', function(evt) {
    console.log(`[main] result is: ${evt.data.result}.`);
}, false);

worker.postMessage({num1: 20, num2: 10});

console.log('[main] Main is initialized.');
// worker.js
self.addEventListener('message', function (evt) {
    const num1 = evt.data.num1;
    const num2 = evt.data.num2;
    const result = num1 + num2;
    console.log('[worker] num1=' + num1 + ', num2=' + num2);
    self.postMessage({result: result});
}, false);

console.log(`[worker] Worker is initialized.`);

在浏览器里访问,网络请求如下,main.js、worker.js 出现串行加载情况。

从性能优化的角度来讲,串行加载往往是比较糟糕的实践,它有可能会抵消掉前面为了性能优化而付出的努力。

优化:解决worker串行加载的问题

最早写worker的科普文《【HTML5】webworker简介》,还是2013年的时候,这么多年过去了,从常理推断,类似的问题应该早有解决方案了。刚好前阵子把flv.js的源码稍微撸了一遍,flv.js支持启用worker,里面其实就有答案。

flv.js源码分析跟本文无关,后面有时间打算专门写一篇,这里直接抛结论,关键伪代码如下:

const workerBlob = new Blob([workerFileContent], { type:'text/javascript' });
const workerObjectUrl = URL.createObjectURL(workerBlob);
const worker = new Worker(workerObjectUrl);

下面看具体源码,github完整示例可点击这里

首先,worker.js 保持不变,只是main.js进行了微调:

const workerFileContent = `./worker.js`; // 注意,这行代码会通过脚本替换成实际的文件内容
const workerBlob = new Blob([workerFileContent], { type:'text/javascript' });
const workerObjectUrl = URL.createObjectURL(workerBlob);
const worker = new Worker(workerUrl);

worker.addEventListener('message', function(evt) {
    console.log(`[main] result is: ${evt.data.result}.`);
}, false);

worker.postMessage({num1: 20, num2: 10});

console.log('[main] Main is initialized.');

转换脚本比较简单:

const fs = require('fs');
const workerFilePath = './worker.js';
const mainFilePath = './main.js';
const bundleFilePath = './bundle.js';

const workerFileContent = fs.readFileSync(workerFilePath, 'utf8').toString();
const mainFileContent = fs.readFileSync(mainFilePath, 'utf8').toString();
const bundleFileContent = mainFileContent.replace('./worker.js', workerFileContent);

fs.writeFileSync(bundleFilePath, bundleFileContent);

同样,在浏览器里查看效果,搞定。

相关链接

本文例子:https://github.com/chyingp/blog/tree/master/demo/2019.10.23-load-worker-via-objectUrl

URL.createObjectURL():https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL

发表评论

邮箱地址不会被公开。 必填项已用*标注

Protected with IP Blacklist CloudIP Blacklist Cloud