你知道JavaScript中的Web Worker和Blob嗎?

前言

來啦老鐵喊儡!

今天咱們暫不學(xué)習(xí)Spring Boot拨与,如果您對Spring Boot感興趣,麻煩移步艾猜、關(guān)注專題:

Spring Boot全家桶

近期在搭建公司W(wǎng)eb視頻編輯器SDK的接口自動化框架過程中捻悯,遇到幾個新名詞,是我之前所不了解的淤毛,他們就是:

  • Web Worker今缚;

  • Blob;

筆者自詡對Node.js還算玩的溜低淡,沒曾想在前端javascript還是半個文盲姓言,您說咱們是不是得補一補?

整體學(xué)習(xí)路徑

  1. Web Worker的由來蔗蹋;
  2. 什么是Web Worker?
  3. 動手實踐Web Worker何荚;
  4. 什么是Blob?
  5. 使用Blob動態(tài)創(chuàng)建Web Worker;

1. Web Worker的由來猪杭;

為了解釋W(xué)eb Worker的由來餐塘,我們先一起來學(xué)習(xí)一下js單線程、異步的原理皂吮。簡單寫了點js代碼并簡單作了一下圖戒傻,用于解釋js單線程、異步的原理:

js單線程蜂筹、異步原理圖

一起來理解一下:

js是單線程的需纳、異步的?

眾所周知狂票,js卻是是單線程的候齿,也的確是異步的,很多人都深信不疑闺属,但是我告訴您慌盯,這句話是錯的,至少不嚴謹掂器!怎么說亚皂?原因是:單線程與異步本身是矛盾的,單線程一定是同步的国瓮,即代碼是一行一行執(zhí)行的灭必!

可是js的確是異步的,這又怎么解釋乃摹?

js本身的確是單線程禁漓、同步的,但瀏覽器不是呀孵睬,瀏覽器是多線程的播歼,瀏覽器為js提供了任務(wù)隊列線程。

js主線程一行一行地執(zhí)行代碼掰读,當遇到耗時的代碼秘狞,就把該任務(wù)丟到瀏覽器提供的任務(wù)隊列里頭叭莫,然后js主線程繼續(xù)往下執(zhí)行代碼匿辩;

當js主線程執(zhí)行完不阻塞的代碼后讥蔽,再到瀏覽器任務(wù)隊列里頭循環(huán)查找那些耗時的任務(wù)執(zhí)行情況帕胆,當耗時的任務(wù)執(zhí)行完畢后粒督,js就能拿到耗時任務(wù)的結(jié)果,也即js主線程才真正完成使命覆积!

因此龟糕,在上述“js單線程沪斟、異步原理圖”中辩蛋,實際的執(zhí)行應(yīng)該是像藍色的箭頭所示呻畸。當js主線程執(zhí)行demo()方法時,先打印出數(shù)字1悼院,接著打印數(shù)字3,最后才打印出數(shù)字2咒循,因為setTimeout是阻塞的(事實上据途,即使setTimeout等待的時間為0,數(shù)字2也是最后打印的)叙甸,如圖:

異步效果
js主線程+瀏覽器的任務(wù)隊列線程颖医,才使js達到了異步的效果!nodejs也是類似的!

可是裆蒸,這跟Web Worker有啥關(guān)系呀熔萧?

js單線程、異步原理圖

仔細看下“js單線程僚祷、異步原理圖”佛致,瀏覽器隊列只有一個,而且既然是隊列辙谜,就需要排隊俺榆,很多業(yè)務(wù)場景下如計算密集型或高延遲任務(wù)中還是不夠用的,這時候就衍生出Web Worker装哆!

2. 什么是Web Worker?

來自網(wǎng)絡(luò)文章:Web Worker 的作用罐脊,就是為 JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker 線程蜕琴,將一些任務(wù)分配給后者運行萍桌。在主線程運行的同時,Worker 線程在后臺運行凌简,兩者互不干擾上炎。等到 Worker 線程完成計算任務(wù),再把結(jié)果返回給主線程号醉。這樣的好處是反症,一些計算密集型或高延遲的任務(wù)辛块,被 Worker 線程負擔(dān)了,主線程(通常負責(zé) UI 交互)就會很流暢铅碍,不會被阻塞或拖慢润绵。

引入Web Worker后就變成這樣了:
Web Worker

每個Web Worker單獨占用一個線程(即多線程),Web Worker線程與Web Worker線程間是互不干擾的胞谈!

想象一下尘盼,在未引入Web Worker的時候,假設(shè)任務(wù)7是計算密集型或高延遲的任務(wù)烦绳,而任務(wù)8是某UI交互卿捎,則UI交互就會被計算密集型或高延遲的任務(wù)所阻塞,頁面很可能就是卡住径密、無響應(yīng)的狀態(tài)午阵!

而引入Web Worker之后,計算密集型或高延遲的任務(wù)被安排到了新的Web Worker線程享扔,并不占用瀏覽器的任務(wù)隊列底桂,即像任務(wù)8就不會被阻塞,頁面就能很流暢惧眠!

需要注意的是:由于每個Web Worker均占用新的線程籽懦,而線程就會占用系統(tǒng)資源,因此氛魁,Web Worker一旦使用完畢暮顺,就應(yīng)該關(guān)閉,不應(yīng)該過度使用秀存!

Web Worker有一些限制(來源于網(wǎng)絡(luò)文章)捶码,具體是:

1. 同源限制;

分配給 Worker 線程運行的腳本文件应又,必須與主線程的腳本文件同源宙项。

2. DOM 限制;

Worker 線程所在的全局對象株扛,與主線程不一樣尤筐,無法讀取主線程所在網(wǎng)頁的 DOM 對象,也無法使用document洞就、window盆繁、parent這些對象。但是旬蟋,Worker 線程可以navigator對象和location對象油昂。

3. 通信聯(lián)系;

Worker 線程和主線程不在同一個上下文環(huán)境,它們不能直接通信冕碟,必須通過消息完成拦惋。

4. 腳本限制;

Worker 線程不能執(zhí)行alert()方法和confirm()方法安寺,但可以使用 XMLHttpRequest 對象發(fā)出 AJAX 請求厕妖。

5. 文件限制;

Worker 線程無法讀取本地文件挑庶,即不能打開本機的文件系統(tǒng)(file://)言秸,它所加載的腳本,必須來自網(wǎng)絡(luò)迎捺。

3. 動手實踐Web Worker举畸;

1. 編寫html頁面,如:index.html凳枝;
<!DOCTYPE html>
<html>
<head>
    <title>Web Worker實踐</title>
    <meta charset="utf-8">
</head>
<body>

<p>計數(shù): <output id="result"></output></p>
<button onclick="startWorker()">開始計數(shù)</button> 
<button onclick="stopWorker()">停止計數(shù)</button>

<button onclick="alert(123)">Alert操作</button>

</body>
</html>

<script>
    let worker;
    
    function startWorker() {
        worker = new Worker('./index.js');
        worker.onmessage = function(event) {
            document.getElementById('result').innerHTML = event.data;
        }
    }
    
    function stopWorker() { 
        worker.terminate();
    }
</script>
2. 編寫要worker的任務(wù)抄沮,如:index.js;
let i= 0;

function count() {
    i += 1;
    postMessage(i);
    setTimeout(count(), 1000);
}

count();
3. 搭建一個簡單服務(wù)器岖瑰;

根據(jù)Web Worker的文件限制合是,我們需要搭建一個簡單服務(wù)器,來運行我們的例子锭环。服務(wù)器搭建可參考:

直接復(fù)制其代碼,織入新建的main.js文件即可:

var http = require('http');
var fs = require('fs');
var url = require('url');
 
// 創(chuàng)建服務(wù)器
http.createServer( function (request, response) {  
   // 解析請求泊藕,包括文件名
   var pathname = url.parse(request.url).pathname;
   
   // 輸出請求的文件名
   console.log("Request for " + pathname + " received.");
   
   // 從文件系統(tǒng)中讀取請求的文件內(nèi)容
   fs.readFile(pathname.substr(1), function (err, data) {
      if (err) {
         console.log(err);
         // HTTP 狀態(tài)碼: 404 : NOT FOUND
         // Content Type: text/html
         response.writeHead(404, {'Content-Type': 'text/html'});
      }else{             
         // HTTP 狀態(tài)碼: 200 : OK
         // Content Type: text/html
         response.writeHead(200, {'Content-Type': 'text/html'});    
         
         // 響應(yīng)文件內(nèi)容
         response.write(data.toString());        
      }
      //  發(fā)送響應(yīng)數(shù)據(jù)
      response.end();
   });   
}).listen(8080);
 
// 控制臺會輸出以下信息
console.log('Server running at http://127.0.0.1:8080/');

index.html辅辩、index.js、main.js在同一個文件目錄下即可娃圆!

4. Web Worker演示玫锋;

1). 啟動項目:

node main.js
啟動項目

2). 訪問html頁面;

訪問html頁面

3). 驗證Web Worker工作情況讼呢;

  • 開始計數(shù):
開始計數(shù)
  • 點擊Alert操作按鈕并等待幾秒:
點擊Alert操作按鈕并等待幾秒
  • 關(guān)閉Alert窗口:
關(guān)閉Alert窗口
  • 停止計數(shù):
停止計數(shù)

我們會發(fā)現(xiàn)撩鹿,當alert窗口彈出時,Worker在后臺還一直執(zhí)行悦屏,并不會阻礙瀏覽器的其他事件节沦!停止計數(shù)后,再次開始計數(shù)也是從1開始數(shù)础爬。

通過這個簡單的例子甫贯,我們就能感受到Web Worker的效果,當計數(shù)Worker為其他計算密集型或高延遲的任務(wù)時看蚜,效果應(yīng)該會更加明顯叫搁!

4. 什么是Blob?

對于什么是Blob,讀者可自行查閱資料,我們這里只針對Web Worker來介紹Blob渴逻。

上面的例子中疾党,我們將模擬的計算密集型或高延遲的任務(wù)寫在index.js文件中,
但是如果在實際生產(chǎn)中惨奕,我們只能運行一個事先寫好的js文件雪位,那這worker的局限性就太大了,太不靈活了墓贿,事實上茧泪,我們往往需要一個動態(tài)創(chuàng)建Web Worker的能力,通常我們利用Blob以及URL.createObjectURL()來提供動態(tài)創(chuàng)建Web Worker的能力聋袋!

5. 使用Blob動態(tài)創(chuàng)建Web Worker队伟;

要使用Blob動態(tài)創(chuàng)建Web Worker,簡單的說就是:

let worker = new Worker('./index.js');

要變成:

let blob = new Blob(XXX)
let worker = new Worker(URL.createObjectURL(blob));

XXX指的是要動態(tài)執(zhí)行的任務(wù)幽勒!

動手擼一個示例:
將index.html進行改造:

<!DOCTYPE html>
<html>
<head>
    <title>Web Worker實踐</title>
    <meta charset="utf-8">
</head>
<body>

<p>計數(shù): <output id="result"></output></p>
<button onclick="startWorker()">開始計數(shù)</button> 
<button onclick="stopWorker()">停止計數(shù)</button>

<button onclick="alert(123)">Alert操作</button>

</body>
</html>

<script>
    function createBlob() {
        function count() {
            i+=1;
            postMessage(i);
            setTimeout("count()", 1000);
        }
        let blob = new Blob(["let i= 0;" + count.toString() + ' count()'], {type: 'text/javascript'});
        return URL.createObjectURL(blob);
    }
    

    let worker;
    function startWorker() {
        worker = new Worker(createBlob());
        worker.onmessage = function(event) {
            document.getElementById('result').innerHTML = event.data;
        }
    }
    
    function stopWorker() { 
        worker.terminate();
    }
</script>

簡單的說URL.createObjectURL();就是把代碼與url做個映射關(guān)聯(lián)嗜侮,url的返回就是Blob對象包裝的任務(wù)代碼!

運行后跟之前是一樣的效果喲啥容!
利用Blob動態(tài)創(chuàng)建Worker

這樣锈颗,我們就擺脫了需要事先寫好js文件的束縛,能夠動態(tài)地創(chuàng)建Web Worker嘍咪惠!

綜上击吱,我們用一句話概括Web Worker和Blob:

  • Web Worker:使得js有多線程效果!
  • Blob:可以利用Blob動態(tài)創(chuàng)建Web Worker!

如果本文對您有幫助遥昧,麻煩點贊覆醇、關(guān)注!

謝謝炭臭!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末永脓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鞋仍,更是在濱河造成了極大的恐慌常摧,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件威创,死亡現(xiàn)場離奇詭異落午,居然都是意外死亡,警方通過查閱死者的電腦和手機那婉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門板甘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人详炬,你說我怎么就攤上這事盐类∧椋” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵在跳,是天一觀的道長枪萄。 經(jīng)常有香客問我,道長猫妙,這世上最難降的妖魔是什么瓷翻? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮割坠,結(jié)果婚禮上齐帚,老公的妹妹穿的比我還像新娘。我一直安慰自己彼哼,他們只是感情好对妄,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著敢朱,像睡著了一般剪菱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拴签,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天孝常,我揣著相機與錄音,去河邊找鬼蚓哩。 笑死构灸,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的岸梨。 我是一名探鬼主播冻押,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盛嘿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起括袒,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤次兆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后锹锰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芥炭,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年恃慧,在試婚紗的時候發(fā)現(xiàn)自己被綠了园蝠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡痢士,死狀恐怖彪薛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤善延,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布少态,位于F島的核電站,受9級特大地震影響易遣,放射性物質(zhì)發(fā)生泄漏彼妻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一豆茫、第九天 我趴在偏房一處隱蔽的房頂上張望侨歉。 院中可真熱鬧,春花似錦揩魂、人聲如沸幽邓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颊艳。三九已至,卻和暖如春忘分,著一層夾襖步出監(jiān)牢的瞬間棋枕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工妒峦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留重斑,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓肯骇,卻偏偏與公主長得像窥浪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笛丙,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361