Foreword
A few days ago, I and a discussion of this issue almost friends know, I felt this is very interesting, so write this article as a record
The article ideas and project code derived from the Friends of Scouting @ simon3000 , I have to be modified to meet the needs of a more understandable.
As used herein, the code has been authorized parties , see:
Thank you very much his understanding and encouragement
On the initial code address
(Page into the project, under which the original-version directory is the author of the original code)
Webworker create problems brought about by JS file and path
Webworker, in fact, I have always felt that the use of relatively stiff, because it seems you need to create additional JS file to run, as follows
var worker =new Worker('work.js’)
This means that you need to create an additional js file. In this way it makes me feel a bit "old-fashioned." Because the ability to manipulate files JS poor, if you want to create the file, of course, there are methods, reference: https://github.com/eligrey/FileSaver.js/
But the question is, if you want to create the file, JS file creation often inseparable download! I was just trying to "quietly" to create a file, but the results JS suddenly pop up a download box when it is created, it can be unbearable. Ah, uncomfortable. (Here should be [difficult for me] expression package).
That is, this time webWorker is "static", is an extra-JS files, is constrained.
Four times the conversion, will become a regular function, which imposes WebWorker
But @ simon3000 recommendations let me shines! He told me that, based on his experience using webworker-loader (webpack technology stack) , there is a continuous conversion of a direct way to become a regular function WebWorker
This is a very exciting information.
Just look at his actions:
// 文件名为main.js function work () { onmessage = ({data: {message}}) => { console.log ('i am worker, receive:' + message); postMessage ({result: 'message from worker'}); }; } const runWorker = f => { const worker = new Worker ( URL.createObjectURL (new Blob ([`(${f.toString ()})()`])) ); worker.onmessage = ({data: {result}}) => { console.log ('i am main thread, receive:' + result); }; worker.postMessage ({message: 'message from main thread'}); }; const testWorker = runWorker (work);
这段代码是我在他的代码基础上简化的
输出结果:
用Promise和闭包的方式去改造
我们再让它更通用一些,用Promise和闭包的方式去改造它,把runworker函数改造成一个makeworker函数
// 文件名为index.js function work () { onmessage = ({data: {jobId, message}}) => { console.log ('i am worker, receive:-----' + message); postMessage ({jobId, result: 'message from worker'}); }; } const makeWorker = f => { let pendingJobs = {}; const worker = new Worker ( URL.createObjectURL (new Blob ([`(${f.toString ()})()`])) ); worker.onmessage = ({data: {result, jobId}}) => { // 调用resolve,改变Promise状态 pendingJobs[jobId] (result); // 删掉,防止key冲突 delete pendingJobs[jobId]; }; return (...message) => new Promise (resolve => { const jobId = String (Math.random ()); pendingJobs[jobId] = resolve; worker.postMessage ({jobId, message}); }); }; const testWorker = makeWorker (work); testWorker ('message from main thread').then (message => { console.log ('i am main thread, i receive:-----' + message); });
输出结果
总结
这次探讨告诉我们什么道理呢?
-
第一,function.toString得到的并不是一个没有意义的字符串,它是完全可以被用来运行的
-
第二,通过这种方式,webworker不需要借助额外的JS文件了,webworker完全动态化和自由化,你可以在主线程中创建任意个webworker!
-
第三,我通过这次的交谈了解到一个道理,编程除了考量逻辑思维,信息差也是考量的一大因素。我之前也想过用webworker做这些事情,可是我不知道能用这样的四重转换呀!我也不知道function.toString得到的字符串居然是有作用的。信息差,也是会造成差距的。所以工程上也经验和前瞻也同样重要。
其他参考资料
-
worker-loader源码: https://github.com/webpack-contrib/worker-loader