据我所知,web worker需要写在一个单独的JavaScript文件中,并像这样调用:
new Worker('longrunning.js')
我正在使用闭包编译器来合并和缩小我所有的JavaScript源代码,我不希望将我的worker放在单独的文件中进行分发。有什么办法可以做到吗?
new Worker(function() {
//Long-running work here
});
既然一级函数对JavaScript如此重要,为什么标准的后台工作方式必须从web服务器加载整个其他JavaScript文件呢?
使用Blob方法,对于工人工厂来说是这样的:
var BuildWorker = function(foo){
var str = foo.toString()
.match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
return new Worker(window.URL.createObjectURL(
new Blob([str],{type:'text/javascript'})));
}
所以你可以这样使用它…
var myWorker = BuildWorker(function(){
//first line of worker
self.onmessage(){....};
//last line of worker
});
编辑:
我只是进一步扩展了这个想法,以便更容易地进行跨线程通信:bridge -worker.js。
编辑2:
上面的链接是我创建的一个要点。后来又有人把它变成了真正的回购。
对于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 );
有一些答案,但这里是另一个内联版本。
注意:“self”参数纯粹是为了检测目的而做的修饰,实际的工作代码从第一个大括号开始,self是正常的
inlineWorker (
"hello world",// initial message to send to worker
function(self){
// inline worker code.
self.onmessage = function (e) {
self.postMessage("thinking...");
for (var i=0;i<100000000;i++) {
var r = Math.random();
}
self.postMessage(e.data.toUpperCase());
}
},function(e){
// optional message handler
document.getElementById("log").innerHTML= "from worker:"+e.data;
});
function inlineWorker (msg,fn,onMsg) {
var
w=window,
U=!!w.webkitURL?w.webkitURL:w.URL,
src=fn.toString(),
s=src.indexOf('{'),
e=src.lastIndexOf('}'),
worker = new Worker(U.createObjectURL(
new Blob([ src.substring(s+1,e-1) ], { type: "text/javascript" })
));
if (typeof onMsg==="function") {
worker.addEventListener("message",onMsg);
}
if (msg) {
worker.postMessage(msg);
}
return worker;
}
<div id="log"></div>