前言
前幾天,我和一位知乎網(wǎng)友討論這個(gè)問(wèn)題的時(shí)候,覺得這非常有意思,所以寫了這篇文章作為記錄 本文的思路和項(xiàng)目代碼來(lái)源于知友 @simon3000
<https://www.zhihu.com/people/simon3000/activities>,我加以修飾以更符合理解的需求。 ?
本文所用代碼已經(jīng)得到當(dāng)事人授權(quán),請(qǐng)看: 非常感謝他的理解和鼓勵(lì) ?
作者初始代碼地址
?(進(jìn)入項(xiàng)目頁(yè)面,里面的original-version目錄下就是作者的最初的代碼)
https://github.com/penghuwan/flex-webworker
<https://github.com/penghuwan/flex-webworker>
?
通過(guò)JS文件和路徑創(chuàng)建webworker帶來(lái)的問(wèn)題
Webworker,我其實(shí)一直覺得用法比較生硬,因?yàn)樗坪跣枰獎(jiǎng)?chuàng)建額外的JS文件才能運(yùn)行,就像下面這樣 var worker =new
Worker('work.js’) ?
這意味著,你需要額外創(chuàng)建一個(gè)js文件。這種方式讓我覺得有些“古板”。因?yàn)镴S操縱文件的能力很差,如果想要?jiǎng)?chuàng)建文件,當(dāng)然方法也有,參考:
https://github.com/eligrey/FileSaver.js/
<https://github.com/eligrey/FileSaver.js/> ?
但是問(wèn)題在于,如果想要?jiǎng)?chuàng)建文件,JS的文件創(chuàng)建往往離不開下載!我原本只是想“悄無(wú)聲息”地創(chuàng)建一個(gè)文件,但結(jié)果JS在創(chuàng)建的時(shí)候突然彈出一個(gè)下載框,這可讓人受不了。啊,難受。
(此處應(yīng)有[我太難了]表情包)。 ? 也就是,這時(shí)候的webWorker是“靜態(tài)”的,是需要額外JS文件的,是受約束的。 ?
四次轉(zhuǎn)換,將一個(gè)普通函數(shù)強(qiáng)行變成WebWorker
但是 @simon3000 <https://www.zhihu.com/people/simon3000/activities>
的建議讓我眼前一亮!他告訴我,根據(jù)他使用webworker-loader(webpack技術(shù)棧)的經(jīng)驗(yàn)
,有一種連續(xù)轉(zhuǎn)換的方式可以直接將一個(gè)普通函數(shù)變成WebWorker
? 這真是一個(gè)令人興奮的信息。 ? 試看看他的操作: // 文件名為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); 這段代碼是我在他的代碼基礎(chǔ)上簡(jiǎn)化的 ?
輸出結(jié)果: ?
用Promise和閉包的方式去改造
我們?cè)僮屗ㄓ靡恍肞romise和閉包的方式去改造它,把runworker函數(shù)改造成一個(gè)makeworker函數(shù) // 文件名為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}}) => { // 調(diào)用resolve,改變Promise狀態(tài)
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); });
?
輸出結(jié)果 ?
總結(jié)
這次探討告訴我們什么道理呢?
* 第一,function.toString得到的并不是一個(gè)沒(méi)有意義的字符串,它是完全可以被用來(lái)運(yùn)行的
* 第二,通過(guò)這種方式,webworker不需要借助額外的JS文件了,webworker完全動(dòng)態(tài)化和自由化,你可以在主線程中創(chuàng)建任意個(gè)webworker!
* 第三,我通過(guò)這次的交談了解到一個(gè)道理,編程除了考量邏輯思維,信息差也是考量的一大因素
。我之前也想過(guò)用webworker做這些事情,可是我不知道能用這樣的四重轉(zhuǎn)換呀!我也不知道function.toString得到的字符串居然是有作用的。信息差,也是會(huì)造成差距的。所以工程上也經(jīng)驗(yàn)和前瞻也同樣重要。
其他參考資料
* worker-loader源碼:?https://github.com/webpack-contrib/worker-loader
<https://github.com/webpack-contrib/worker-loader>
熱門工具 換一換
