這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 JS是一門單線程語言,單線程就意味著,所有的任務需要排隊,前一個任務結束,才會執行下一個任務。這樣所導致的問題是:如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染載入阻塞的覺。為瞭解決這個問題,JS中出現了同步和異 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前言
JS是一門單線程語言,單線程就意味著,所有的任務需要排隊,前一個任務結束,才會執行下一個任務。這樣所導致的問題是:如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染載入阻塞的覺。為瞭解決這個問題,JS中出現了同步和非同步。他們的本質區別是:一條流水線上各個流程的執行順序不同。在講JS任務執行機制前,先要瞭解一下什麼是同步任務與非同步任務。
同步任務:即主線程上的任務,按照順序由上⾄下依次執⾏,當前⼀個任務執⾏完畢後,才能執⾏下⼀個任務。
非同步任務:不進⼊主線程,⽽是進⼊任務隊列的任務,執行完畢之後會產生一個回調函數,並且通知主線程。當主線程上的任務執行完後,就會調取最早通知自己的回調函數,使其進入主線程中執行。
1. 事件迴圈Event Loop概念介紹
- 事件迴圈Event Loop又叫事件隊列,兩者是一個概念
事件迴圈指的是js代碼所在運行環境(瀏覽器、nodejs)編譯器的一種解析執行規則。事件迴圈不屬於js代碼本身的範疇,而是屬於js編譯器的範疇,在js中討論事件迴圈是沒有意義的。換句話說,js代碼可以理解為是一個人在公司中具體做的事情, 而 事件迴圈 相當於是公司的一種規章制度。 兩者不是一個層面的概念。
2. 微任務、巨集任務概念介紹
- 微任務與巨集任務就屬於js代碼的範疇
- js代碼主要分為兩大類: 同步代碼、非同步代碼
- 非同步代碼又分為:微任務與巨集任務
3. 事件迴圈Event Loop執行機制
-
1.進入到script標簽,就進入到了第一次事件迴圈.
-
2.遇到同步代碼,立即執行
-
3.遇到巨集任務,放入到巨集任務隊列里.
-
4.遇到微任務,放入到微任務隊列里.
-
5.執行完所有同步代碼
-
6.執行微任務代碼
-
7.微任務代碼執行完畢,本次隊列清空
-
尋找下一個巨集任務,重覆步驟1
- 以此反覆直到清空所以巨集任務,這種不斷重覆的執行機制,就叫做事件迴圈
畫了一張圖來描述事件迴圈
4.易錯點
(1). promise本身是一個同步的代碼(只是容器),只有它後面調用的then()方法裡面的回調才是微任務
(2). await右邊的表達式還是會立即執行,表達式之後的代碼才是微任務, await微任務可以轉換成等價的promise微任務分析
(3). script標簽本身是一個巨集任務
, 當頁面出現多個script標簽的時候,瀏覽器會把script標簽作為巨集任務來解析
看到這裡,對事件迴圈應該有所瞭解了,給大家看幾道面試題。
一.
1.先執行主線程上的log(1) 2.當有兩個await時,只有第一個await右邊的代碼會立即執行log(4),後面的幾行代碼都會放入微任務隊列中。 3.執行主線程上的log(6) 4.執行第4行至第6行的微任務
二.
1.先執行主線程上的1,5,7 2.主線程的同步任務執行完畢後,會先執行微任務。執行Promise的then方法里的代碼,列印6 3.微任務執行完畢後,最後執行定時器里的巨集任務,列印2,3,4
三.
1.先執行主線程上的同步代碼,列印1 2.執行第9行的函數,進⼊async1內部,async1其實是聲明瞭⼀個promise,promise是同步代碼,會順序執⾏列印async2函數里的4 ,只有.then⾥⾯的代碼會加⼊微任務隊列⾥,這⾥相當於執⾏了async2()之後,再將後面的代碼加⼊⼀個微任務隊列中。 3.回主線程中,遇到setTimeout(),加⼊到巨集任務隊列 4.主線程繼續往後執⾏,前⾯說過,promise是同步代碼,.then後⾯的回調會加⼊微任務隊列,所以會列印13⾏的7 5.主線程執⾏完成,開始執⾏微任務隊列內的任務,遵循先進先出的原則,列印第四⾏的2。然後接著執行第5行第二個awaite右邊的代碼,列印5。第6行這個時候就被加入微任務隊列。 6.接著會執行第二個微任務,也就是16行代碼,列印8。第17行的then這個時候也會加入微任務隊列。再依次執行第6行和第17行的兩個微任務,列印3和9 7.微任務執⾏結束,開始執⾏巨集任務setTimeout,列印11⾏的6.
總結
- 所有同步任務都在主線程上執行,形成一個執行棧(call stack)。
- 遇到非同步任務, 進入非同步處理模塊並註冊回調函數; 等到指定的事件完成(如ajax請求響應返回, setTimeout延遲到指定時間)時,非同步處理模塊會將這個回調函數移入非同步任務隊列。
- 當棧中的代碼執行完畢,執行棧中的任務為空時,主線程會先檢查微任務隊列中是否有任務,如果有,就將微任務隊列中的所有任務依次執行,直到微任務隊列為空; 之後再檢查巨集任務隊列中是否有任務,如果有,則取出第一個巨集任務加入到執行棧中,之後再清空執行棧,檢查微任務,以此迴圈,直到全部的任務都執行完成。