今天主要講一下eventloop在瀏覽器中與在node中運行的機制,首先,不得不來講一下,下面幾個名詞的概念。javascript
Node.js是一個基於 ChromeV8引擎的JavaScript運行環境(runtime),Node不是一門語言,而是讓js運,行在後端的運行時,而且不包括javascript全集,由於在服務端中不包含DOM和BOM,Node也提供了一些新的模塊例如http,fs模塊等。css
Node.js 使用了事件驅動、非阻塞式 I/O 的模型,使其輕量又高效而且Node.js 的包管理器 npm,是全球最大的開源庫生態系統。java
高併發,是指在同一時間併發訪問服務器node
I/O密集指的是文件操做、網絡操做、數據庫,相對的有CPU密集,CPU密集指的是邏輯處理運算、壓縮、解壓、加密、解密ajax
用戶界面-包括地址欄、前進/後退按鈕、書籤菜單等數據庫
瀏覽器引擎-在用戶界面和呈現引擎之間傳送指令(瀏覽器的主進程)npm
渲染引擎,也被稱爲瀏覽器內核(瀏覽器渲染進程)後端
一個插件對應一個進程(第三方插件進程)promise
GPU提升網頁瀏覽的體驗(GPU進程)瀏覽器
渲染引擎內部是多線程的,內部包含兩個最爲重要的線程ui線程和js線程。
這裏要特別注意ui線程和js線程是互斥的,由於JS運行結果會影響到ui線程的結果。
ui更新會被保存在隊列中等到js線程空閒時當即被執行。
javascript在最初設計時設計成了單線程,爲何不是多線程呢?
若是多個線程同時操做DOM那豈不會很混亂?這裏所謂的單線程指的是主線程是單線程的,因此在Node中主線程依舊是單線程的。
js只能是單線程的 不能兩個線程同時操做一個dom
ui進程與js進程是互斥的,不能同時執行,執行js後空閒下來了,再去執行css
瀏覽器事件觸發線程(用來控制事件循環,存放setTimeout、瀏覽器事件、ajax的回調函數)
定時觸發器線程(setTimeout定時器所在線程)
異步HTTP請求線程(ajax請求線程)
以下圖所示:
下列代碼中,函數是放到棧中的,看看它的執行順序
function fn1() {
let a = 1;
fn2();
function fn2() {
console.log(a);
let b = 2;
function fn3() {
debugger;
console.log(b);
}
fn3();
}
}
fn1();
複製代碼
執行結果以下圖所示:
常見的(macro-task)宏任務:setTimeout setImmediate(只兼容ie) MessageChannel
常見的(micro-task)微任務:promise.then (MutationObserver);
瞭解了以上幾個名詞的概念以後,下面重點來了,先看一下EventLoop在瀏覽器中的運行機制
Promise.resolve('1').then(data => { console.log('第一個promise') });
setTimeout(() => {
console.log('setTimeout1')
Promise.resolve('2').then(data => { console.log('第二個promise') });
});
setTimeout(() => {
console.log('setTimeout2');
});
複製代碼
代碼運行的結果爲:
第一個promise
setTimeout1
第二個promise
setTimeout2
複製代碼
1,setTimeout有一個4ms的最短期,也就是說無論你設定多少,反正最少都要間隔4ms才運行裏面的回調,因此先執行了第一個promise異步回調,輸出了第一個promise
2,setTimeout到運行時間了,輸出了setTimeout1,
3,依次輸出了第二個promise(Promise的任務會在當前事件循環末尾中執行)
4,最後,第二個setTimeout到時間了,輸出了setTimeout2
複製代碼
EventLoop在node中的運行機制
nextTick(微任務)是隊列切換時執行的
setTimeout和setImmediate順序是不固定,看node準備時間
setImmediate(() => {
console.log('setImmediate1')
setTimeout(() => {
console.log('setTimeout1')
}, 0);
})
setTimeout(()=>{
process.nextTick(()=>console.log('nextTick'))
console.log('setTimeout2')
setImmediate(()=>{
console.log('setImmediate2')
})
},0);
複製代碼
第一種狀況,若是先執行了setImmediate函數,那麼它的執行順序爲:
setImmediate1
setTimeout2
setTimeout1
nextTick
setImmediate2
複製代碼
1,根據上圖所示,若是先執行了setImmediate回調,把setImmediate1輸出了,
2,接下來,會執行setTimeout回調,輸出setTimeout2,
3,接着輸出setTimeout1,接着微任務nextTick,
4,最後,輸出setImmediate2
複製代碼
第二種狀況,若是先執行了setTimeout函數,那麼它的執行順序爲:
setTimeout2
nextTick
setImmediate1
setImmediate2
setTimeout1
複製代碼
1,根據上圖所示,若是先執行了setTimeout回調,把setTimeout2輸出了,
2,接下來,會執行poll輪詢,那就是輸出了nextTick,
3,接下來執行check隊列中setImmediate函數,把setImmediate1輸出了,check隊列裏的內容得先執行完,才能切換下一個隊列,因此輸出了setImmediate2,
4,最後循環到了setTimeout回調,輸出了setTimeout1
複製代碼
關於eventloop在不一樣環境中運行的機制,首先要對上述提到的,隊列&棧、微任務&宏任務要有深刻的理解,但願這篇內容對你們有所幫助,固然也但願你們若是有什麼問題,能夠隨時加關注,進行討論!