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

歡迎訪問 生活随笔!

生活随笔

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

javascript

JavaScript事件循环探索

發布時間:2025/3/20 javascript 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript事件循环探索 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一直對js的事件循環不是很清晰,最近看了JavaScript忍者秘籍的第13章后,有了一些感悟,特此總結一下,分享給大家。

單線程

眾所周知,JavaScript是單線程執行模型,同一時刻只能執行一個代碼片段,一個任務開始后知道運行完成,不會被其他任務中斷。當一個任務花費的時間很長的話,用戶就會明顯的感覺到卡頓。瀏覽器為了解決這個問題引入了事件循環的概念(Event Loop)。

事件循環

事件循環具有至少兩個隊列處理任務。任務分為兩類,宏任務(macro-task)和微任務(micro-task)。

1.宏任務代表一個個離散、獨立的工作單元,運行完之后,瀏覽器可以繼續其他的調度。包括:創建文檔對象,解析HTML,執行JavaScript,以及各種事件…… 2.微任務是更小的任務,主要用戶更新應用程序的狀態,必須在瀏覽器任務繼續執行其他任務之前執行。微任務需要盡可能快地通過異步方式執行,同時不能產生全新的微任務。包括promise、回調函數、DOM發生變化……

僅包含宏任務

// 主線程JavaScript運行15ms btn1.addEventListener('click', function() {運行 8ms}, false); btn2.addEventListener('click', function() {運行 5ms}, false);

現在假設主線程運行15ms, 在第5ms單擊btn1,在第12ms的時候單擊btn2。基于單線程執行模型,單擊按鈕之后不會立即執行對應的處理函數,因為一個任務一旦開始就不會被另一個任務中斷。因此,在主線程執行的15ms期間,按鈕的單擊處理函數放入隊列。當主線程執行完成也就是15ms之后,程序開始處理微任務,因為當前不存在微任務,跳過此步驟,開始執行更新UI。

之后進入第二次循環,也就是開始執行btn1的處理函數,需要運行8ms,btn2處理函數在隊列中等待。當btn1處理函數執行完之后,瀏覽器檢查微任務是否存在和是否更新UI,刪除任務隊列里的btn1的處理函數。

最后進入第三次循環,開始執行btn2的處理函數,需要運行5ms,處理函數執行完之后,檢查微任務和是否需要更新UI,刪除任務隊列里的btn2的處理函數,最終任務隊列為空,循環結束。

同時含有宏任務和微任務

// 主線程JavaScript運行15ms btn1.addEventListener('click', function() {Promise.resolve().then(() => {運行 4ms });運行 8ms }, false); btn2.addEventListener('click', function() {運行 5ms}, false);

本例中在btn1的事件處理函數里增加了一個立即兌現的Promise,需要運行4ms。

現在代碼的執行順序為:

  • 主線程執行15ms,在5ms和12ms的時候分別將處理函數放入任務隊列,更新UI。
  • 15m后處理btn1事件處理函數,發現Promise,放入微任務隊列,btn1事件處理函數繼續執行8ms,檢查微任務隊列發現有Promise回調函數,然后開始執行Promise回調函數,運行4ms,繼續檢查微任務隊列,如果為空,檢查是否需要更新UI,進入下一輪循環。
  • 處理btn2的事件處理函數……
  • 計時器

    // 主線程JavaScript運行18ms setTimeout(function() {運行6ms; }, 10); setInterval(function() {運行8ms; }, 10); btn1.addEventListener('click', function() {運行 10ms}, false);

    ?代碼的執行過程是什么呢?

    現在我們想象一下主線程代碼需要運行18ms,在第6ms的時候用戶點擊了按鈕,在第10ms延遲計時器到期,間隔計時器第一次觸發。

    我們知道一個任務一旦開始執行,就無法被其他任務中斷。所以,6ms將事件處理函數加入隊列,10ms分別將延遲計時器和間隔計時器回調放入隊列。運行到18m主線程執行完畢,檢查微任務隊列和更新UI,進入下一個時間循環。開始執行btn1事件回調,運行10ms,這時候在btn1事件回調運行的過程中,間隔計時器第二次到期,但是任務隊列里面已經有一個間隔計時器處理函數,所以忽略這個處理函數。btn1事件回調運行結束,檢查微任務隊列和更新UI,進入下一個事件循環。開始執行延遲計時器處理函數,運行6ms,在這個過程中間隔計時器第三次到期,但是由于任務隊列已經有了處理函數,繼續忽略。延遲計時器處理函數運行完畢,檢查微任務隊列和更新UI,進入下一個事件循環。現在開始執行間隔計時器處理函數,運行8ms,在這期間間隔計時器第四次到期,這時候任務隊列里沒有處理函數,所以將這次的處理函數放入任務隊列,間隔定時器處理函數運行完成,檢查微任務隊列和更新UI,進入下一個事件循環,然后重復運行間隔定時器……

    通過以上的執行過程我們發現,我們只能控制計時器何時被加入隊列,而無法控制何時執行。

    最后,JavaScript的事件循環是這門語言非常重要的基礎,由于我水平有限以上只是簡單總結了一下它的執行過程。大家可以深入研究一下Nodejs的事件循環

    總結

    以上是生活随笔為你收集整理的JavaScript事件循环探索的全部內容,希望文章能夠幫你解決所遇到的問題。

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