日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务

發布時間:2023/12/4 HTML 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

隊列在前端中的應用

  • 一、隊列是什么
  • 二、應用場景
  • 三、前端與隊列:事件循環與任務隊列
    • 1、event loop
    • 2、JS如何執行
    • 3、event loop過程
    • 4、 DOM 事件和 event loop
    • 5、event loop 總結
  • 四、宏任務和微任務
    • 1、引例
    • 2、宏任務和微任務
      • (1)常用的宏任務和微任務
      • (2)宏任務和微任務的優先級
      • (3)代碼實現微任務和宏任務
      • (4)event loop和DOM渲染
      • (5)微任務、宏任務和DOM渲染的關系
      • (6)為何微任務更早
  • 五、結束語

隊列 在日常生活中的應用非常廣泛,比如我們最熟悉不過的食堂排隊打飯、擊鼓傳花等等問題。同時,它在前端中的應用也非常廣泛,比如,事件循環 Event loop 、JS異步中的任務隊列。

所以呢,對于前端來說, 隊列 結構是一個必學的知識點。在接下來的這篇文章中,將講解關于 隊列 在前端中的應用。

一、隊列是什么

隊列是一種先進先出(FIFO)的線性表。它只允許在表的一端進行插入,而在另一端刪除元素。

二、應用場景

  • 需要先進先出的場景。
  • 比如:食堂排隊打飯、火車站排隊買票、JS異步中的任務隊列、計算最近請求次數……。

三、前端與隊列:事件循環與任務隊列

1、event loop

event loop,也被稱為事件循環事件輪詢。因為JS是單線程運行的,且異步需要基于回調來實現,所以, event loop 就是異步回調的實現原理。

2、JS如何執行

JS在程序中的執行遵循以下規則:

  • 從前到后,一行一行執行
  • 如果某一行執行報錯,則停止下面代碼的執行
  • 先把同步代碼執行完,再執行異步

一起來看一個實例:

console.log('Hi');setTimeout(function cb1(){console.log('cb1'); //cb1 即callback回調函數 }, 5000);console.log('Bye');//打印順序: //Hi //Bye //cb1

從上例代碼中可以看到, JS 是先執行同步代碼,所以先打印 Hi 和 Bye ,之后執行異步代碼,打印出 cb1 。

以此代碼為例,下面開始講解 event loop 的過程。

3、event loop過程

對于上面這段代碼,執行過程如下圖所示。

從上圖中可以分析出這段代碼的運行軌跡。首先 console.log('Hi') 是同步代碼,直接執行并打印出 Hi 。接下來繼續執行定時器 setTimeout ,定時器是異步代碼,所以這個時候瀏覽器會將它交給 Web APIs 來處理這件事情,因此先把它放到 Web APIs 中,之后繼續執行 console.log('Bye') , console.log('Bye') 是同步代碼,在調用堆棧 Call Stack 中執行,打印出 Bye 。

到這里,調用堆棧 Call Stack 里面的內容全部執行完畢,當調用堆棧的內容為空時,瀏覽器就會開始去任務隊列尋找下一個任務,此時任務隊列就會去 Web API 里面尋找任務,遵循先進先出原則,找到了定時器,且定時器里面是回調函數 cb1 ,于是把回調函數 cb1 傳入任務隊列中,此時 Web API 也空了,任務隊列里面的任務就會傳入到調用堆棧里Call Stack 里執行,最終打印出 cb1 。

4、 DOM 事件和 event loop

先來看兩段代碼。

console.log('Hi');setTimeout(function cb1(){console.log('cb1'); //cb 即 callback }, 5000);console.log('Bye');/*輸出結果: Hi Bye cb1 */ <button id = "btn1">提交</button><script> console.log('Hi');document.getElementById('btn1').click(function(e){console.log('button clicked');});console.log('Bye'); </script>/*輸出結果: Hi Bye button clicked */

以上這兩段代碼中,第一段是關于 setTimeout 的事件循環,第二段是關于 DOM 事件的事件循環。那有小伙伴就會有疑問說, DOM 事件不是異步操作嗎,為什么輸出結果依然是在最后呢?

其實, DOM 事件確實不是異步操作,但是它也使用回調,基于 event loop 事件循環機制,所以當我們點擊的時候,會觸發 DOM 事件,并進行打印。

總結下 DOM 事件和 event loop 的區別:

  • JS 是單線程的;
  • 異步( setTimeout , ajax 等)使用回調,基于 event loop ;
  • DOM 事件不是異步,但也使用回調,基于 event loop 。

5、event loop 總結

初階認識完event loop后,來做個總結:

總結event loop 過程1

  • 同步代碼,一行一行放在 Call Stack 執行;
  • 遇到異步,會先“記錄”下,等待時機(定時、網絡請求);
  • 時機到了,就移動到 Callback Queue。

總結event loop 過程2

  • 如果 Call Stack 為空(即同步代碼執行完),則 event Loop 開始工作;
  • 輪詢查找 Callback Queue ,如果有則移動到 Call Stack 執行;
  • 然后繼續輪詢查找(跟永動機一樣,不斷循環查找)。

四、宏任務和微任務

1、引例

我們先來看一段代碼。

console.log(100); setTimeout(() => {console.log(200); }); Promise.resolve().then(() => {console.log(300); }); console.log(400); /*** 打印結果:* 100* 400* 300* 200*/

在上面這段代碼中,第一個和第二個打印結果是基于同步,我們都知道要打印 100 和 400 ,但是第三個和第四個打印結果,理論上按照打印順序應該是 200 和 300 才是,為什么是打印 300 和 200 呢?這就涉及到一個宏任務和微任務的問題。接下來將對宏任務和微任務進行講解。

2、宏任務和微任務

(1)常用的宏任務和微任務

名稱舉例(常用)
宏任務script、setTimeout 、setInterval 、setImmediate、Ajax、DOM事件、I/O、UI Rendering
微任務process.nextTick()、Promise、async/await

上述的 setTimeout 和 setInterval 等都是任務源,真正進入任務隊列的是他們分發的任務。

注意: 微任務執行時機比宏任務要早!!

(2)宏任務和微任務的優先級

優先級

  • setTimeout = setInterval 一個隊列
  • setTimeout > setImmediate
  • process.nextTick > Promise

(3)代碼實現微任務和宏任務

for(const macroTask of macroTaskQueue){handleMacroTask();for(const microTask of microTaskQueue){handleMicroTask();} }

(4)event loop和DOM渲染

在上面的主題三第4點中講過, DOM 事件基于回調,也是基于 event loop 機制的。那DOM事件在程序執行到什么時候,才會渲染呢?

同樣來看這段代碼。

<button id = "btn1">提交</button><script> console.log('Hi');document.getElementById('btn1').click(function(e){console.log('button clicked');});console.log('Bye'); </script>/*輸出結果: Hi Bye button clicked */

由上圖可知,當程序調用??臻e時,程序會先嘗試去進行 DOM 渲染,最后再觸發 Event Loop 機制。所以,在上面的這段代碼中,程序會先打印同步代碼 Hi 和 Bye ,等待同步代碼打印完畢后,會再查找 DOM 事件,進行渲染,最后再觸發 event loop 。

總結 event loop 和 DOM 渲染的關系:

  • 在程序執行的時候, JS 是單線程的,且和 DOM 渲染共用一個線程;

  • 所以 JS 在執行的時候,得留一些時機提供給 DOM 渲染。

  • 每次 Call Stack 清空(即每次輪詢結束),表示同步任務執行完成;

  • 程序會一直給 DOM 重新渲染的機會, DOM 結構如有改變則重新渲染;

  • 然后再去觸發下一次 Event Loop 。

(5)微任務、宏任務和DOM渲染的關系

先了解微任務、宏任務和 DOM 渲染的關系:

  • 宏任務: DOM 渲染觸發,如 setTimeout 。
  • 微任務: DOM 渲染觸發,如 Promise 。

我們先來演示現象,再追究其原理。

1)演示1

const $p1 = $('<p>一段文字</p>'); const $p2 = $('<p>一段文字</p>'); const $p3 = $('<p>一段文字</p>'); $('#container').append($p1).append($p2).append($p3);//微任務:DOM 渲染前觸發 Promise.resolve().then(() => {console.log('length', $('#container').children().length);alert('Promise then');//(alert 會阻斷 js 執行, 也會阻斷 DOM 渲染,便于查看效果) });

以上這段代碼中,瀏覽器顯示效果如下。

在圖中可以看出,微任務 promise 在 DOM 渲染前就觸發了,所以 DOM 對應的文字還沒顯示時, Promise 就已經打印。

2)演示2

const $p1 = $('<p>一段文字</p>'); const $p2 = $('<p>一段文字</p>'); const $p3 = $('<p>一段文字</p>'); $('#container').append($p1).append($p2).append($p3);//宏任務:DOM 渲染后觸發 setTimeout(() => {console.log('length1', $('#container').children().length);alert('SetTimeout');//(alert 會阻斷 js 執行, 也會阻斷 DOM 渲染,便于查看效果) });

以上這段代碼中,瀏覽器顯示效果如下。

在圖中可以看出,當 DOM 對應的文字已經顯示時, setTimeout 彈框才出現,所以宏任務 setTimeout 是在 DOM 渲染后(即 DOM 渲染并顯示結束)才觸發。

講到這里,回到我們前面所說的知識點。

  • 宏任務: DOM 渲染觸發,如 setTimeout 。
  • 微任務: DOM 渲染觸發,如 Promise 。

從上面的演示后,相信大家應該明白了微任務、宏任務和 DOM 的關系。在第一個演示中,微任務 Promise 在 DOM 還沒有渲染時就觸發了,所以微任務都是在 DOM 渲染前觸發。在第二個演示中,宏任務 setTimeout 在文字顯示結束后才觸發 alert ,所以微任務都是在 DOM 渲染后才進行觸發。

(6)為何微任務更早

理解完微任務和宏任務與DOM的關系后,我們也大致基本了解了為什么微任務比宏任務更早。接下來我們在從 eventloop 層面來看,為什么微任務會比宏任務更早,為什么會在DOM渲染前就開始觸發呢?

先用一張圖來表示。

微任務在執行時不會經過 Web APIs ,它會把它放到一個叫做 micro task queue(即宏任務隊列)當中。且微任務是ES6` 語法規定的,宏任務是由瀏覽器規定的,所以它會比宏任務更早。

到這里,我們講完了 event loop 以及與其相關的宏任務和微任務,下面我們再用一張圖來總結實際運用的執行順序。

從上圖中可以得出結論:

第一步,程序先程序 Call Stack 里面的內容,待 Call Stack 清空時,執行當前的微任務;

第二步,程序找到微任務隊列的任務,執行微任務;

第三步,待微任務執行完畢后,嘗試執行DOM渲染;

第四步, DOM 渲染結束后,觸發 event loop ,執行宏任務。

五、結束語

隊列在前端中的應用可以算是很非常頻繁了?;旧衔覀儗懙漠惒胶瘮翟趫绦羞^程中,都會涉及到事件循環問題。且在前端的面試當中,經常會被問到 event loop 、事件循環或者事件輪詢是什么,很多面試者就很容易在這塊內容吃虧。相信通過上文的學習,大家都對 eventloop 、微任務和宏任務有了一個更深的認識。

隊列在前端中的應用就講到這里啦!如有不理解或者文章有誤歡迎評論區留言或私信我交流~

  • 關注公眾號 星期一研究室 ,第一時間關注學習干貨,更多有趣的專欄待你解鎖~

  • 如果這篇文章對你有用,記得點個贊加個關注再走哦~

  • 我們下期見!🥂🥂🥂

總結

以上是生活随笔為你收集整理的详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。