天天看點

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

例子:下題你可能會認為100ms之後,由于a變成了false,是以while就中止了,實際不是這樣,因為JS是單線程的,是以進入while循環之後,沒有「時間」(線程)去跑定時器了,是以這個代碼跑起來是個死循環!

var 
           

事件循環是JavaScript實作異步的具體解決方案,其中同步代碼直接執行;異步函數先放在異步隊列中,待同步函數執行完畢後,輪循執行異步隊列中的回調函數。

事件循環中,每進行一次循環操作稱為tick,每一個tick的任務處理模型關鍵步驟如下:

  • 執行一個宏任務(棧中沒有就從事件隊列中擷取)
  • 執行過程中如果遇到微任務,就将它添加到微任務的隊列中
  • 宏任務執行完畢後,立即執行目前微任務隊列中的所有微任務(依次執行)
  • 目前宏任務執行完畢,開始檢查渲染,然後GUI線程接管渲染
  • 渲染完畢後,JS線程接續接管,開始下一個宏任務(從事件隊列中擷取)
js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

(macro)task宏任務:包括script、setTimeout、I/O、UI互動等

micro task微任務:包括Promise.then、Mutation observer、process.nextTick(node.js環境等)。async/await和Promise實作延遲執行,并在每個task結束時執行。

在每一個事件循環之前,microtask隊列總是被清空。

代碼中出現setTimeout、async/await、Promise等函數正确的執行順序是怎樣的呢?

先看一道經典面試題目:

async 
           

控制台運作結果為:

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
           
js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

注:上圖為Chrome75.0.3770.142執行結果截圖,如果浏覽器版本為Chrome61.0.3163.100(低于v73)則promise2先于async1 end列印(最新版本的firefox火狐亦是如此)。

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

分析執行過程流程圖:

"執行整體代碼"開始後掃到task放入task queue,掃到微任務放入micro task queue。

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

分析要點主要記住3點:

(1)Promise中的異步展現在then和catch中,故寫在Promise中的代碼是被當做同步任務立即執行的;

(2)而在async/await中,在出現await之前其代碼也是立即執行的。帶async關鍵字的函數僅僅是把return值包裝成promise傳回,其他并無不同之處;

(3)await是讓出線程的标志:await後面的表達式會先執行一遍(await等的是右側表達式的結果),将await語句之後的代碼加入到micro task中,然後就會跳出整個async函數來執行後續代碼。

用上例方法來分析另一道例題:

例2:

setTimeout(() => console.log('setTimeout1'), 0);
setTimeout(() => {
    console.log('setTimeout2');
    Promise.resolve().then(() => {
        console.log('promise2');
        Promise.resolve().then(() => {
            console.log('promise3');
        })
        console.log(5)
    })
    setTimeout(() => console.log('setTimeout4'), 0);
}, 0);
setTimeout(() => console.log('setTimeout3'), 0);
Promise.resolve().then(() => {
    console.log('promise1');
})
           
js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?
js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

最後,我們再來一道在node中的異步題目吧:

async 
           
(macro)task宏任務:包括script、setTimeout、I/O、UI互動、setImmediate(nodejs環境中)等 micro task微任務:包括Promise.then、Mutation observer、process.nextTick(node.js環境等)。async/await和Promise實作延遲執行,并在每個task結束時執行。在每一個事件循環之前,microtask隊列總是被清空。
js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

windows下的node10.16.3運作結果如上圖,Mac的node12.6.0運作結果稍有出入:

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

具體表現在 async1 end和promise3孰先孰後、setImmediate和setTimeout3孰先孰後的差異。

本文參考連結:

8張圖讓你一步步看清 async/await 和 promise 的執行順序​segmentfault.com 浏覽器和NodeJS中不同的Event Loop · Issue #234 · kaola-fed/blog​github.com

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

Tasks, microtasks, queues and schedules​jakearchibald.com

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

更快的異步函數和 Promise​v8.js.cn 令人費解的 async/await 執行順序​juejin.im 用一道大廠面試題帶你搞懂事件循環機制​mp.weixin.qq.com

js return false 之後不能停止執行_浏覽器是如何執行JavaScript異步代碼的?

繼續閱讀