据我所知,web worker需要写在一个单独的JavaScript文件中,并像这样调用:
new Worker('longrunning.js')
我正在使用闭包编译器来合并和缩小我所有的JavaScript源代码,我不希望将我的worker放在单独的文件中进行分发。有什么办法可以做到吗?
new Worker(function() {
//Long-running work here
});
既然一级函数对JavaScript如此重要,为什么标准的后台工作方式必须从web服务器加载整个其他JavaScript文件呢?
我发现CodePen目前不语法高亮内联<script>标签,不是type="text/javascript"(或没有类型属性)。
因此,我设计了一个类似但略有不同的解决方案,使用带break的标记块,这是摆脱<script>标记而不创建包装器函数(这是不必要的)的唯一方法。
<!DOCTYPE html>
<script id="worker1">
worker: { // Labeled block wrapper
if (typeof window === 'object') break worker; // Bail if we're not a Worker
self.onmessage = function(e) {
self.postMessage('msg from worker');
};
// Rest of your worker code goes here.
}
</script>
<script>
var blob = new Blob([
document.querySelector('#worker1').textContent
], { type: "text/javascript" })
// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
console.log("Received: " + e.data);
}
worker.postMessage("hello"); // Start the worker.
</script>
https://developer.mozilla.org/es/docs/Web/Guide/Performance/Using_web_workers
// Syntax: asyncEval(code[, listener])
var asyncEval = (function () {
var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");
oParser.onmessage = function (oEvent) {
if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }
delete aListeners[oEvent.data.id];
};
return function (sCode, fListener) {
aListeners.push(fListener || null);
oParser.postMessage({
"id": aListeners.length - 1,
"code": sCode
});
};
})();
对于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 );
我发现CodePen目前不语法高亮内联<script>标签,不是type="text/javascript"(或没有类型属性)。
因此,我设计了一个类似但略有不同的解决方案,使用带break的标记块,这是摆脱<script>标记而不创建包装器函数(这是不必要的)的唯一方法。
<!DOCTYPE html>
<script id="worker1">
worker: { // Labeled block wrapper
if (typeof window === 'object') break worker; // Bail if we're not a Worker
self.onmessage = function(e) {
self.postMessage('msg from worker');
};
// Rest of your worker code goes here.
}
</script>
<script>
var blob = new Blob([
document.querySelector('#worker1').textContent
], { type: "text/javascript" })
// Note: window.webkitURL.createObjectURL() in Chrome 10+.
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
console.log("Received: " + e.data);
}
worker.postMessage("hello"); // Start the worker.
</script>
这是一个有点离题的答案,但是……您可能不需要使用网络工作者来处理浏览器上的长时间工作。
让我们假设你想要运行几次繁重的计算(就像你对数组做的那样):
const heavyFct = () => {let i = 0; while(i<1e8) {++i}}
for (let i = 0; i < 100; ++i) {
heavyFct();
}
这将冻结您的浏览器。
为了避免这种情况,我们可以这样依赖setTimeout:
const desync = (i = 0) => {
if (i >= 100) {return}
heavyFct();
setTimeout(() => desync(i + 1), 0);
}
desync();
现在,您可以在不冻结计算机的情况下运行繁重的计算