事件循環

一、關於javascript
javascript是一門 單線程 語言,在最新的HTML5中提出了Web-Worker,但javascript是單線程這一核心仍未改變。因此一切javascript版的"多線程"都是用單線程模擬出來的,一切javascript多線程都是紙老虎!
二、javascript事件循環
既然js是單線程,那就像只有一個窗口的銀行,客戶須要排隊一個一個辦理業務,同理js任務也要一個一個順序執行。若是一個任務耗時過長,那麼後一個任務也必須等着。那麼問題來了,假如咱們想瀏覽新聞,可是新聞包含的超清圖片加載很慢,難道咱們的網頁要一直卡着直到圖片徹底顯示出來?所以聰明的程序員將任務分爲兩類:javascript

JS分爲同步任務和異步任務
同步任務都在主線程上執行,造成一個執行棧
主線程以外,事件觸發線程管理着一個任務隊列,只要異步任務有了運行結果,就在任務隊列之中放置一個事件。
一旦執行棧中的全部同步任務執行完畢(此時JS引擎空閒),系統就會讀取任務隊列,將可運行的異步任務添加到可執行棧中,開始執行java

事件循環是經過任務隊列的機制來進行協調的。一個 Event Loop 中,能夠有一個或者多個任務隊列(task queue),一個任務隊列即是一系列有序任務(task)的集合;每一個任務都有一個任務源(task source),源自同一個任務源的 task 必須放到同一個任務隊列,從不一樣源來的則被添加到不一樣隊列。 setTimeout/Promise 等API即是任務源,而進入任務隊列的是他們指定的具體執行任務。程序員

宏任務:promise

macro)task(又稱之爲宏任務),能夠理解是每次執行棧執行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調並放到執行棧中執行)。

瀏覽器爲了可以使得JS內部(macro)task與DOM任務可以有序的執行,會在一個(macro)task執行結束後,在下一個(macro)task 執行開始前,對頁面進行從新渲染,流程以下:
(macro)task->渲染->(macro)task->...
(macro)task主要包含:script(總體代碼)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 環境)

微任務:瀏覽器

microtask(又稱爲微任務),能夠理解是在當前 task 執行結束後當即執行的任務。也就是說,在當前task任務後,下一個task以前,在渲染以前。

因此它的響應速度相比setTimeout(setTimeout是task)會更快,由於無需等渲染。也就是說,在某一個macrotask執行完後,就會將在它執行期間產生的全部microtask都執行完畢(在渲染前)。

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 環境)

運行機制:多線程

在事件循環中,每進行一次循環操做稱爲 tick,每一次 tick 的任務處理模型是比較複雜的,但關鍵步驟以下:

執行一個宏任務(棧中沒有就從事件隊列中獲取)
執行過程當中若是遇到微任務,就將它添加到微任務的任務隊列中
宏任務執行完畢後,當即執行當前微任務隊列中的全部微任務(依次執行)
當前宏任務執行完畢,開始檢查渲染,而後GUI線程接管渲染
渲染完畢後,JS線程繼續接管,開始下一個宏任務(從事件隊列中獲取)

流程圖以下:
圖片描述異步

兩道題 讓你所有理解事件循環async

console.log('1')
  setTimeout(function() {
    console.log('2')
    process.nextTick(function() {
      console.log('3')
    })
    new Promise(function(resolve) {
      console.log('4')
      resolve()
    }).then(function() {
      console.log('5')
    })
  })
  process.nextTick(function() {
    console.log('6')
  })
  new Promise(function(resolve) {
    console.log('7')
    resolve()
  }).then(function() {
    console.log('8')
  })
  setTimeout(function() {
    console.log('9')
    process.nextTick(function() {
      console.log('10')
    })
    new Promise(function(resolve) {
      console.log('11')
      resolve()
    }).then(function() {
      console.log('12')
    })
  })
  
  第二題
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

注意:
async function async1() {                        
    console.log('async1 start');
    await async2();                   
    console.log('async1 end');
}
等同於
async function async1() {
    console.log('async1 start');
    Promise.resolve(async2()).then(() => {
            console.log('async1 end');
    })
}
相關文章
相關標籤/搜索