据我所知,web worker需要写在一个单独的JavaScript文件中,并像这样调用:
new Worker('longrunning.js')
我正在使用闭包编译器来合并和缩小我所有的JavaScript源代码,我不希望将我的worker放在单独的文件中进行分发。有什么办法可以做到吗?
new Worker(function() {
//Long-running work here
});
既然一级函数对JavaScript如此重要,为什么标准的后台工作方式必须从web服务器加载整个其他JavaScript文件呢?
对于Node.js实现,可以使用以下对Trincot答案的改编。再次注意,Function.prototype.callAsWorker()接受一个thisArg和参数,就像Function.prototype.call()一样,并返回一个承诺。
const { Worker } = require ( 'worker_threads' );
Function.prototype.callAsWorker = function ( ...args ) {
return new Promise( ( resolve, reject ) => {
const code = `
const { parentPort, workerData } = require ( 'worker_threads' );
parentPort.postMessage( ( ${this.toString()} ).call( ...workerData ) )
`;
const worker = new Worker( code, { eval: true, workerData: args } );
worker.on('message', ( msg ) => { resolve( msg ), worker.terminate() } );
worker.on('error', ( err ) => { reject( err ), worker.terminate() } );
worker.on('exit', ( code ) => {
if ( code !== 0 ) {
reject( new Error( `Worker stopped with exit code ${code}.` ) );
}
});
});
}
// Demo
function add( ...nums ) {
return nums.reduce( ( a, b ) => a + b );
}
// Let the worker execute the above function, with the specified arguments
let result = await add.callAsWorker( null, 1, 2, 3 );
console.log( 'result: ', result );
所以我认为我们现在有了另一个很酷的选择,这要感谢ES6中的模板文字。这允许我们省去额外的worker函数(及其奇怪的作用域),只需将用于worker的代码编写为多行文本,就像我们用来存储文本的情况一样,但实际上不需要使用文档或DOM来实现。例子:
const workerScript = `
self.addEventListener('message', function(e) {
var data = e.data;
console.log('worker recieved: ',data);
self.postMessage('worker added! :'+ addOne(data.value));
self.close();//kills the worker
}, false);
`;
下面是该方法的其余要点。
请注意,我们可以将任何我们想要的额外函数依赖项拉入worker,只需将它们收集到一个数组中,并对每个函数运行. tostring,将它们简化为字符串(只要它们是函数声明就可以工作),然后将其添加到脚本字符串中。这样,我们就不必导入我们可能已经捆绑到正在编写的代码范围中的脚本。
这个特定版本唯一的缺点是lints无法检测service worker代码(因为它只是一个字符串),这对于“单独的worker函数方法”来说是一个优势。