据我所知,web worker需要写在一个单独的JavaScript文件中,并像这样调用:

new Worker('longrunning.js')

我正在使用闭包编译器来合并和缩小我所有的JavaScript源代码,我不希望将我的worker放在单独的文件中进行分发。有什么办法可以做到吗?

new Worker(function() {
    //Long-running work here
});

既然一级函数对JavaScript如此重要,为什么标准的后台工作方式必须从web服务器加载整个其他JavaScript文件呢?


当前回答

http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers

如果您希望动态地创建工作人员脚本,或者创建一个自包含的页面,而不必创建单独的工作人员文件,该怎么办?使用Blob(),您可以通过将工作代码的URL句柄创建为字符串,将工作代码“内联”到与主逻辑相同的HTML文件中


BLOB inline worker的完整示例:

<!DOCTYPE html> <script id="worker1" type="javascript/worker"> // This script won't be parsed by JS engines because its type is javascript/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>

其他回答

http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers

如果您希望动态地创建工作人员脚本,或者创建一个自包含的页面,而不必创建单独的工作人员文件,该怎么办?使用Blob(),您可以通过将工作代码的URL句柄创建为字符串,将工作代码“内联”到与主逻辑相同的HTML文件中


BLOB inline worker的完整示例:

<!DOCTYPE html> <script id="worker1" type="javascript/worker"> // This script won't be parsed by JS engines because its type is javascript/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>

尝试使用jThread。https://github.com/cheprasov/jThread

// You can use simple calling like this
jThread(
    function(arr){
        //... some code for Worker
        return arr;
    }
    ,function(arr){
        //... done code
    }
)( [1,2,3,4,5,6,7] ); // some params

对于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>

有一些答案,但这里是另一个内联版本。

注意:“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>