event - 事件 loop - 循環,既然叫事件循環,那麼循環的點在哪? 循環的是一個又一個的任務隊列,這些任務隊列由宏任務和微任務構成
一次事件處理中,最多處理一個宏任務,可是會處理全部的微任務,任務開始後,會將內部全部的宏觀函數加到宏觀隊列等待,會將全部的圍觀函數加到微觀隊列等待,當前宏任務處理完畢後,開始逐個處理微任務,當微任務執行處理完成,會檢查是否須要更新ui,若是是則從新渲染ui。以後再次檢查宏觀任務隊列中的下一個宏觀任務,取出來而且執行promise
瀏覽器的渲染,不一樣瀏覽器處理是不一樣的,可是大部分瀏覽器選擇通常是一秒鐘60幀率(也就是60fps),這意味着瀏覽器會在16ms左右渲染一幀,因此咱們單個任務和該任務的全部附屬微任務都應該在16ms內完成,以達到顯示平滑流暢。瀏覽器
console.time("settimeout"); setTimeout(() => { console.log('settimeout執行') console.timeEnd("settimeout"); }, 1000); for (let a = 0; a < 50000; a++) { console.log(a) }
time會輸出多少呢?這種事件是怎麼觸發的?app
代碼是在一秒鐘後才加入事件隊列,以後等待執行。怎麼證實,很簡單咱們在拿出一個定時器異步
console.time("settimeout"); console.time("settimeout2"); setTimeout(() => { console.log('settimeout執行') console.timeEnd("settimeout"); }, 1000); setTimeout(() => { console.log('settimeout2執行') console.timeEnd("settimeout2"); }, 1); for (let a = 0; a < 50000; a++) { console.log(a) }
明明後聲明的定時器2,卻先執行了,不知道有沒有發現,定時器1和定時器2執行時間,很接近!!!這很重要,爲何會這樣,這就是今天所說的事件隊列,當1毫秒時候,定時器2被加入了事件隊列,當一秒鐘時候定時器1被加入事件隊列,而後for執行完後,隊列中下一個任務爲定時器2,可是他只有一個console故而很快,因此拿出了定時器進行執行。再來看個額外例子,來鞏固下:async
console.time("settimeout"); console.time("settimeout2"); setTimeout(() => { console.log('settimeout執行') console.timeEnd("settimeout"); }, 1000); for (let a = 0; a < 50000; a++) { console.log(a) } setTimeout(() => { console.log('settimeout2執行') console.timeEnd("settimeout2"); }, 1);
枯燥無味的定義基本就這樣,咱們來從實踐來作分析函數
從練習題來講oop
console.log(1) setTimeout(function () { console.log(2) setTimeout(function () { console.log(3) }) }) setTimeout(function () { console.log(4) }) console.log(5)
第一次運行以後
學習
這時當前主進程隊列已經結束,開始檢測微任務隊列是否還有未完成的任務,發現微任務隊列已經空了因此,當前宏任務隊列結束,開始下一組宏任務優化
settimeout2任務完結,檢查當前微任務隊列爲空,開始下一組宏任務ui
因此最終答案爲:
1,5,2,4,3
console.log(1) setTimeout(function () { console.log(2) setTimeout(function () { console.log(3) }) }) setTimeout(function () { console.log(4) }) console.log(5)
這樣就會輸出1,5,2,3,4
tips: setTimeout寫的1000不等於他就是在上一次事件結束後的1000ms,而是以他聲明開始就進行計時的。不過這不是本篇文章的核心,咱們不深究他的邏輯,繼續看第二個例子
console.log(1) setTimeout(() => { console.log('2') Promise.resolve(4).then((res) => console.log(res)) }, 0); setTimeout(() => { console.log('3') }, 0);
主進程執行完畢,檢查微任務隊列爲空,當前宏任務結束,開啓下一組宏任務
settimeout宏任務執行完畢,檢查宏任務隊列,拿出settimeout3的宏任務,將它拿出來執行。這個比較簡單我們就不畫圖了
因此本題答案爲1,2,4,3
let promise = new Promise(function(resolve, reject) { console.log('1'); resolve(); }); promise.then(function() { console.log('2'); }); console.log(3)
檢查宏任務隊列發現爲空,因此本次代碼結束
答案爲:1,3,2
console.log(1); setTimeout(function(){ console.log(2); }, 0); Promise.resolve().then(function(){ console.log(3); }).then(function(){ console.log(4); });
當前宏任務已經結束,查看宏任務隊列中發現還有settimeout沒有執行,將它取出來執行,
輸出2.
因此本題答案爲:1,3,4,2
setTimeout(()=>{ console.log('1'); },0); var obj={ func:function () { setTimeout(function () { console.log('2') },0); return new Promise(function (resolve) { console.log('3'); resolve(); }) } }; obj.func().then(function () { console.log('4') }); console.log('5');
主線進程及其微觀進程執行完畢,會拿出下一組settimeout1執行,執行後會進行檢測微觀隊列,若是沒有則會繼續往下取出settimeout2執行。至此程序結束。
因此本題答案爲:3,5,4,1,2
console.log(1) const p = new Promise(function(resolve, reject) { console.log(2) resolve() }).then(() => { console.log(3) throw(new Error('錯誤')) }).catch(() => { console.log(4) }) console.log(5) setTimeout(() => { console.log(6) }, 0); console.log(7) p.then(() => { console.log(8) throw(new Error('錯誤2')) })
至此,當前宏任務結束。檢查宏任務隊列。取出下一組宏任務,settimeout6,並執行
因此答案爲:1,2,5,7,3,4,8,Error,6
最後留兩道題給你們作學習用。
若是不能一眼看出。能夠像我同樣畫一個圖。進行梳理。本文中爲了代碼整齊,settimeout都是直接簡化爲儘快執行。其實settimeout應該是在到達他聲明的時間時候,才進入宏觀隊列排隊的。
根據如下規則,你將不會在遇到事件隊列的問題
console.log(1) const p = new Promise(function(resolve, reject) { console.log(2) setTimeout(() => { console.log(9) }, 0); resolve() }).then(() => { console.log(3) throw(new Error('錯誤')) }).catch(() => { console.log(4) }) console.log(5) setTimeout(() => { console.log(6) }, 0); console.log(7) p.then(() => { console.log(8) throw(new Error('錯誤2')) })
console.log(1) const p = new Promise(function(resolve, reject) { console.log(2) setTimeout(() => { console.log(9) }, 0); resolve() }).then(() => { console.log(3) throw(new Error('錯誤')) }).catch(() => { console.log(4) }) console.log(5) setTimeout(() => { console.log(6) }, 0); console.log(7) p.then(() => { console.log(8) throw(new Error('錯誤2')) }) requestAnimationFrame(function() { console.log(10) })
怎麼利用這些,在代碼中優化本身的代碼,舉個例子來講
for (let i = 0 ; i<50000;i++) { const div = document.createElement('div') div.innerText = i document.body.appendChild(div) }
function slice(startSplitNumber, total, sliceNumber, cb) { const oneNumber = total/sliceNumber const start = startSplitNumber * oneNumber const end = (startSplitNumber + 1) * oneNumber if (start >= total) return setTimeout(() => { for(let i = start; i < end;i++) { cb(i) } slice(startSplitNumber + 1, total, sliceNumber, cb) }, 0) } slice(0, 50000, 5000, function (current) { const div = document.createElement('div') div.innerText = current document.body.appendChild(div) })