目錄
macrotask的本質
microtask
总结
首頁 web前端 js教程 瀏覽器事件循環的深入了解(程式碼範例)

瀏覽器事件循環的深入了解(程式碼範例)

Nov 12, 2018 pm 05:06 PM
chrome javascript

這篇文章帶給大家的內容是關於瀏覽器事件循環的深入了解(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

瀏覽器的事件循環,前端再熟悉不過了,每天都會接觸的東西。但我以前一直都是死記硬背:事件任務隊列分為macrotask和microtask,瀏覽器先從macrotask取出一個任務執行,再執行microtask內的所有任務,接著又去macrotask取出一個任務執行.. .,這樣一直循環下去。但對於下面的程式碼,我一直在懵逼,setTimeout屬於macrotask,按照上面的規則,setTimeout應該先被取出來執行啊,但是我卻被執行結果打臉了。

<script>
    setTimeout(() => {
        console.log(1)
    }, 0)
    new Promise((resolve) => {
        console.log(2)
        resolve()
    }).then(() => {
        console.log(3)
    })
    // 我曾经的预期是:2 1 3
    // 实际输出:2 3 1
</script>
登入後複製

經過再仔細看別人對任務佇列的介紹,才知道,同步執行的js程式碼其實就算一個macrotask(準確地說是每一個script標籤內的程式碼都是一個macrotask),所以上面的規則中說的先取出一個macrotask執行 是沒有問題的。
網路上很多文章都是像上面這樣解釋的,我也一直認為這是HTML對事件循環的規範,我們記得就是。直到最近看了李銀城大佬的文章(見文末的參考連結),我才恍然大悟,之前看的文章都沒有明確地從瀏覽器的多線程模型這個角度分析,所以讓我們覺得瀏覽器的事件循環是基於上述的約定,但其實這是瀏覽器的多執行緒模型所導致的結果。

macrotask的本質

macrotask本質上是瀏覽器多個執行緒之間通訊的一個訊息佇列
在chrome裡,每個頁面都對應一個進程,該進程又有多個線程,例如js線程、渲染線程、io線程、網路線程、計時器線程等,這些線程之間的通信,則是透過向對方的任務佇列中新增一個任務(PostTask)來實現的。

瀏覽器的各種線程都是常駐線程,它們運行在一個for死循環裡面,每個線程都有屬於自己的若干任務隊列,線程自己或者其它線程都可能通過PostTask向這些任務佇列新增任務,這些執行緒會不斷地從自己的任務佇列中取出任務執行,或是處於睡眠狀態直到設定的時間或是有人PostTask的時候把它們喚醒。

可以簡單地理解為,瀏覽器的各個執行緒都在不停地從自己的任務佇列中取出任務,執行,再取出任務,再執行,這樣無限地循環下去。

以下面的程式碼為例:

<script>
    console.log(1)
    setTimeout(() => {
        console.log(2)
    }, 1000)
    console.log(3)
</script>
登入後複製
  1. 首先,script標籤中的程式碼作為一個任務放入js執行緒的任務佇列,js執行緒被喚醒,然後取出該任務執行

  2. 先執行console.log(1),然後執行setTimeout,向定時器執行緒新增一個任務,接著執行console.log(3),此時js執行緒的任務佇列為空,js執行緒進入休眠

  3. 大約1000ms後,定時器執行緒向js執行緒的任務佇列加入定時任務(定時器的回呼),js執行緒又被喚醒,執行定時回呼函數,最後執行console.log(2)。

可以看到,所謂的macrotask並不是瀏覽器定義了哪些任務是macrotask,瀏覽器各個執行緒只是忠實地循環自己的任務佇列,不停地執行其中的任務而已。

microtask

比起macrotask是瀏覽器的多執行緒模型造成的“假象”,microtask是確實存在的一個佇列,microtask是屬於目前執行緒的,而不是其他執行緒PostTask過來的任務,只是延遲執行了而已(準確地說是放到了目前執行的同步程式碼之後執行),例如Promise.then、MutationObserver都屬於這種情況。

以下面的程式碼為例:

<script>
    new Promise((resolve) => {
       resolve()
       console.log(1)
       setTimeout(() => {
         console.log(2)
       },0)
    }).then(() => {
        console.log(3)
    })
    // 输出:1 3 2
</script>
登入後複製
  1. 首先,script標籤中的程式碼作為一個任務放入js執行緒的任務佇列,js執行緒被喚醒,然後取出該任務執行

  2. 然後執行new Promise以及Promise中的resolve,resolve後,promise的then的回呼函數會作為需要延遲執行的任務,放到目前執行的所有同步程式碼之後

  3. 接著執行setTimeout,在定時器執行緒上新增一個任務

  4. 此時同步程式碼執行完畢,接著執行被延遲執行的任務,也就是promise的then的回呼函數,即執行console.log(3)

  5. 最後,js執行緒的任務隊列為空,js執行緒進入休眠,大約1000ms後,定時器執行緒為js執行緒的任務佇列加入定時任務(定時器的回呼),js執行緒又被喚醒,執行定時回呼函數,即console.log(2)。

总结

通过上面的分析,可以看到,文章开头提到的规则:浏览器先从macrotask取出一个任务执行,再执行microtask内的所有任务,接着又去macrotask取出一个任务执行...,并没有说错,但这只是浏览器执行机制造成的现象,而不是说浏览器按照这样的规则去执行的代码。
这篇文章中的所有干货都来自李银成大佬的文章,我只是按照自己的理解,做了简化描述,方便大家理解,也加深自己的印象。
最后,看了这篇文章,大家能够基于浏览器的运行机制,分析出下面代码的执行结果了吗(ps:不要用死记硬背的规则去分析哟)

console.log('start')

const interval = setInterval(() => {  
  console.log('setInterval')
}, 0)

setTimeout(() => {  
  console.log('setTimeout 1')
  Promise.resolve()
      .then(() => {
        console.log('promise 3')
      })
      .then(() => {
        console.log('promise 4')
      })
      .then(() => {
        setTimeout(() => {
          console.log('setTimeout 2')
          Promise.resolve()
              .then(() => {
                console.log('promise 5')
              })
              .then(() => {
                console.log('promise 6')
              })
              .then(() => {
                clearInterval(interval)
              })
        }, 0)
      })
}, 0)

Promise.resolve()
    .then(() => {  
        console.log('promise 1')
    })
    .then(() => {
        console.log('promise 2')
    })
// 执行结果
/*  start
    promise 1
    promise 2
    setInterval
    setTimeout 1
    promise 3
    promise 4
    setInterval
    setTimeout 2
    promise 5
    promise 6
*/
登入後複製


以上是瀏覽器事件循環的深入了解(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

什麼是Updater.exe在Windows 11/10?這是Chrome進程嗎? 什麼是Updater.exe在Windows 11/10?這是Chrome進程嗎? Mar 21, 2024 pm 05:36 PM

你在Windows上運行的每個應用程式都有一個元件程式來更新它。因此,如果你使用的是谷歌Chrome或谷歌地球,它會運行一個GoogleUpdate.exe應用程序,檢查是否有更新可用,然後根據設定進行更新。然而,如果您不再看到它,而是在Windows11/10的任務管理器中看到一個進程updater.exe,這是有原因的。什麼是Updater.exe在Windows11/10?谷歌已經為其所有應用程式推出了更新,如GoogleEarth、GoogleDrive、Chrome等。這次更新帶來了

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

解決Google瀏覽器無法開啟網頁的方法 解決Google瀏覽器無法開啟網頁的方法 Jan 04, 2024 pm 10:18 PM

谷歌瀏覽器網頁打不開怎麼辦?有很多小夥伴都喜歡上使用谷歌瀏覽器,當然也有部分小伙伴在使用的過程中發現自己無法正常的打開網頁或者說網頁打開的速度很慢,那麼遇到這種情況該怎麼辦呢?下面就跟小編來看看Google瀏覽器網頁打不開的解決方法吧。谷歌瀏覽器網頁打不開的解決方法一為了幫助還沒過關的玩家們,讓我們一起來了解一下具體的解謎方法吧。首先,右鍵點擊右下角的網路圖標,然後選擇「網路和Internet設定」。 2、點擊"乙太網路",接著點擊"更改適配器選項"。 3、點選”屬性“按鈕。 4.雙擊打開i

Chrome的插件擴充功能安裝目錄是什麼 Chrome的插件擴充功能安裝目錄是什麼 Mar 08, 2024 am 08:55 AM

Chrome的插件擴充功能安裝目錄是什麼?正常情況下,Chrome外掛程式擴充功能的預設安裝目錄如下:1、windowsxp中chrome外掛程式預設安裝目錄位置:C:\DocumentsandSettings\使用者名稱\LocalSettings\ApplicationData\Google\Chrome\UserData\Default\Extensions2、windows7中chrome插件預設安裝目錄位置:C:\Users\使用者名稱\AppData\Local\Google\Chrome\User

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何在Chrome和Edge的所有選項卡中搜尋文本 如何在Chrome和Edge的所有選項卡中搜尋文本 Feb 19, 2024 am 11:30 AM

本教學向您展示如何在Windows的Chrome或Edge中找到所有開啟的標籤頁上的特定文字或短語。有沒有辦法在Chrome中所有開啟的標籤頁上進行文字搜尋?是的,您可以使用Chrome中的免費外部Web擴充功能在所有開啟的標籤上執行文字搜索,而無需手動切換標籤。一些擴充功能如TabSearch和Ctrl-FPlus可以幫助您輕鬆實現這項功能。如何在GoogleChrome的所有選項卡中搜尋文字? Ctrl-FPlus是一個免費的擴展,它方便用戶在瀏覽器視窗的所有標籤中搜尋特定的單字、短語或文字。這個擴

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

See all articles