JS單線程:咱們都知道JavaScript它是一個單線程的語言,同一時間只能作一件事。好比:在瀏覽器中,某一時刻咱們在操做DOM,大家這個時刻咱們就不能去運行JavaScript代碼,反過來也是,當咱們在運行JavaScript代碼的時候,咱們也不能去操做DOM,這個也就是JS的單線程。爲何要JS成單線程?由於在瀏覽器環境下,若是是多線程的,也就是操做DOM和運行JavaScript代碼是並行處理的話,假如某個時刻,瀏覽器正在繪製DOM,可是這個時候的JavaScript代碼改變了DOM,這樣就會形成一個不一致,所以JS就被設計成了一門單線程語言。node
雖然JS是單線程,可是它的宿主,咱們的瀏覽器環境(node環境)它是一個多線程的,在瀏覽器和node裏面只有一條JS線程,可是還有不少其餘的線程。以瀏覽器爲例,瀏覽器的常駐線程(以下)大概有前三個:第一個,UI線程,也就是DOM瀏覽器元素的迴流和重繪,這個UI線程與JavaScript線程是互斥的。第二個就是JavaScript線程,單線程的運行JS代碼。第三個是GUI線程,它主要是處理與用戶交互的一些邏輯,好比點擊某一個元素,拖動了或者縮放了這個就是由GUI線程處理的。除此以外還有NetWorker線程,網絡線程,發送ajax請求,發送http請求都是走的network線程。還有File線程,讀取文件。還有一個定時器線程。web
UI線程 - 迴流和重繪 - 與Javascript線程互斥
JavaScript線程 - 單線程運行JavaScript
GUI線程 - 交互線程
Network線程
File線程
定時器線程
這裏可能會有一個問題是ajax請求對於JS來講是異步的,可是JavaScript是單線程的,這樣就涉及到了一個基於事件的驅動。當咱們發起一個網絡請求時,瀏覽器會把這一部分網絡請求交給network線程去處理,而後JavaScript線程等待network的指令驅動。在沒有代碼要運行的狀況下,JavaScript線程始終是空閒的,有了事件驅動以後,它會一直處於一個輪詢的狀態(Event Loop),瀏覽器會不斷查詢目前是否有JavaScript線程須要運行,若是有就運行,沒有就保持閒置。當一個網絡請求發送出去,這個時候的JavaScript線程是處於閒置的,可是瀏覽器仍是會不停的詢問,當network線程結束後,瀏覽器發現有新的JavaScript代碼須要執行,它就會驅動JavaScript的線程去處理網絡請求返回的結果,這個就是JS 基於事件驅動的模型。ajax
Event Loop(事件輪詢圖)瀏覽器
異步是將耗時比較長的任務放置到Event Queue 事件隊列的尾部。安全
WebWorker爲了解決瀏覽器假死這個問題而孕育而生的一項新技術。它是多線程模型,也是基於宿主。它屬於JavaScript線程中的一個子線程,它徹底受主線程控制,可是在WebWorker裏面是不能操做DOM的。由於上面提到的UI線程和JavaScript線程是互斥的,這個互斥也就保證了DOM的惟一性,所以主的基調不能改變,可是須要有一個新的線程來分擔繁雜的計算任務,這個也就是WebWorker。網絡
WebWorker是爲了處理影響UI線程的JavaScript運算。由於在同一時刻,UI線程和JavaScript線程只能有一個在運行,若是這個時候JS的線程承擔過多運算的話,它的耗時就變得很長,這個時候的UI線程是沒有反應的,這樣就形成了頁面的假死。多線程
建立WebWorker異步
const webWorker = new Worker('main.js'); let result = 0; const fibonacci = (n) => { if (n <= 1) return 1; return fibonacci(n - 1) + fibonacci(n - 2); } result = fibonacci(10); console.log('result', result);
向WebWorker發送消息(數據)oop
webWorker.postMessage({ number : 10 });
WebWorker接收消息post
webWorker.addEventListener('message', event => { console.log('received webworker data', event.data); }, false);
WebWorker發送消息(返回數據)
this.postMessage(returnValue);
主線程接收WebWorker消息
webWorker.addEventListener('message', event => { console.log('received webworker data', event.data); }, false);
關閉WebWorker
方式一:在主線程關閉WebWorker webWorker.terminate(); 方式二:在子線程,WebWorker內部本身調用本身的close方法,再也不接收新的 Macrotask(宏任務) this.close();
importScripts('./one.js', './two.js');
webWorker.addEventListener('error', error => { console.error(error.filename, error.lineno, error.message); });