chrome事件迴圈的自問自答

来源:https://www.cnblogs.com/walkermag/archive/2023/07/21/17570671.html
-Advertisement-
Play Games

打開前端項目中的 package.json,會發現眾多工具已經占據了我們開發日常的各個角落,它們的存在於我們的開發而言是不可或缺的。有沒有想過這些工具的功能是如何實現的呢?沒錯,抽象語法樹 (Abstract Syntax Tree) 就是上述工具的基石。 ...


chrome事件迴圈的自問自答

目錄

1. 巨集任務有哪些?

  • 事件回調 (js調用的 click box.click()
  • XHR或網路請求回調
  • 定時器的回調
  • I/O回調
  • history相關回調
  • MessageChannel的message回調

在合適時機,這些巨集任務會被推入巨集任務隊列;每一次事件迴圈會從巨集任務隊列中取一個任務執行。

history.back回調:

<button id='box'>forward</button>
<button id='box2'>back</button>

<script>
  var box = document.getElementById('box');
  var box2 = document.getElementById('box2');
  box.addEventListener('click',()=>{
    history.pushState('state',null,'?page=1');
  })

  window.addEventListener('popstate',function (ev) {
    console.log('popstate');
  })
  box2.addEventListener('click',()=>{
    history.back();
    setTimeout(()=>{
      console.log('timeout');
    })
  })
</script>

MessageChannel的message回調

<button id='btn'>btn</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
  var channel = new MessageChannel();
    channel.port1.onmessage = function onmessage1 (){
      console.log('postMessage')
      Promise.resolve().then(function promise1 (){
          console.log('promise')
      })
    };
    setTimeout(function setTimeout2(){
      console.log('setTimeout')
    }, 0)
    channel.port2.postMessage(0);
};
</script>

I/O回調

<input type="file" id="input" multiple>
<script>
  input.addEventListener('change', function () {
    var file = input.files[0]
    var reader = new FileReader()
    reader.onload = function (ev) {
      console.log(reader.result);
    }
    reader.readAsArrayBuffer(file)
  })
</script>

2. 微任務有哪些?

MutationObserver的回調、Promise的then catch finally回調、queueMicrotask.

在合適時機,這些微任務會被推入微任務隊列;每一次事件迴圈會從微任務隊列中取所有任務並執行。

Promise和queueMicrotask不支持IE, MutationObserver支持IE11;

MutationObserver例子:

下麵的代碼中box.textContent = 1的位置不同,代碼的執行順序就不同以驗證MutationObserver為微任務。

<div id='box'>0</div>
<script>
  const box = document.getElementById('box');
  const mo = new MutationObserver(function (mutations) {
    console.log('mutations')
  })
  mo.observe(box, {
    childList: true
  })
  box.onclick = function () {
    // box.textContent = 1;
    Promise.resolve().then(()=>{
      console.log(333)
    })
    box.textContent = 1;
  };
</script>

以下是使用`queueMicrotask`方法手動添加微任務的例子,可以不會對更高優先順序的代碼運行造成干擾。

<div id='box'>0</div>
<script>
  const box = document.getElementById('box');
  box.onclick = function () {
    queueMicrotask(()=>{
      console.log(121212)
    })
    console.log(333)
  };
</script>

3. dom渲染是事件迴圈的一部分麽?

從規範的角度來看,DOM渲染是事件迴圈的一部分,可以將其視為一種渲染任務。

如果巨集任務或者微任務中發生了dom修改,因為一個渲染幀的時間可能遠大於事件迴圈周期,所以不一定在本次事件迴圈會執行渲染任務。

<div id='box'>0</div>
<script>
  const box = document.getElementById('box');
  box.onclick = function () {
    setTimeout(function setTimeout17 () {
      box.textContent = 1;
    }, 0)
    setTimeout(function setTimeout18 () {
      box.textContent = 2;
    }, 0)
  };
</script>

下圖是上面的代碼的執行流程,兩個setTimeout的回調執行代表兩次事件迴圈,在其後面出現了一個新的Task,僅執行了一次佈局(layout)和繪製(paint);

image

4. requestAnimationFrame的回調是巨集任務還是微任務?

requestAnimationFrame的回調函數會在瀏覽器在下一幀渲染之前執行, 既不是巨集任務,也不是微任務, 從規範上看是事件迴圈的一部分,從下圖可以看到一個task下包含了requestAnimationFrame,layout paint, 可將其歸類於渲染任務的一個可選步驟。

<div id='box'>0</div>
<script>
  const box = document.getElementById('box');
  box.onclick = function () {
    setTimeout(function setTimeout17 () {
      box.textContent = 1;
      requestAnimationFrame(()=>{
        console.log(111)
         Promise.resolve().then(()=>{
          console.log(333)
        })
      })
    }, 0)
    setTimeout(function setTimeout18 () {
      box.textContent = 2;
      requestAnimationFrame(()=>{
        console.log(222)
      })
    }, 0)
  };
</script>

上述代碼中添加了兩個requestAnimationFrame,可以看到兩者在一個Task內順序執行;並且回調中的微任務也在這個Task內執行;

image

5. requestIdleCallback的回調是巨集任務還是微任務?

requestIdleCallback是事件迴圈的一部分,從圖中可以看到,requestIdleCallback的回調是一個特殊的任務,這個函數的回調會在瀏覽器空閑時期被調用,所以不是每次迴圈都會執行該任務。

<button id='btn'>btn</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
  requestIdleCallback(function () {
    btn.innerHTML = "sdfsdfs"
    setTimeout(()=>{
      console.log(3)
    },0)
    Promise.resolve().then(()=>{
      console.log(4)
    })
  })
};
</script>

image

該任務的優先順序比較低,多個平行聲明的requestIdleCallback會拆開成單一的task, 兩個連續task之間甚至會被內部的setTimeout插足。

for (let i = 0; i < 10; i++) {
  requestIdleCallback(() => {
    console.log('idle', Date.now() - a)
    setTimeout(()=>{
      console.log(12121)
    })
  })
}

image

6. 事件迴圈圖例

image


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、多表關係 一對多或者多對一 案例:部門與員工的關係 關係:一個部門對應多個員工,一個員工對應一個部門(不考慮跨部門的特殊情況) 實現:在多的一方建立外鍵,指向一的一方的主鍵,這裡員工表是多的的一方,部門表是一的一方 多對多 案例:學生與課程的關係 關係:一個學生可以選修多門課程,一門課程也可以供 ...
  • ORALCE substr函數及substrb與字元集關係 語法 函數用途: SUBSTR函數用來截取從源字元(參數 char)中截取一部分目標字元,截取方式為限定從源字元截取起始位置(參數 positon),並限定截取目標字元長度(參數 substring_length)。substr系列函數計算 ...
  • ## 簡述 本文主要介紹使用 [CloudCanal](https://www.clougence.com?kw=cnblogs_20230721) 做數據遷移同步時如何對特定數據做脫敏處理。 ## 技術點 ### 自定義代碼 CloudCanal 允許用戶上傳業務代碼到數據任務中,完成數據遷移、同 ...
  • 一、哪些因素會成為系統的瓶頸 CPU:如果存在大量的計算,他們會長時間不間斷的占用CPU資源,導致其他資源無法爭奪到CPU而響應緩慢,從而帶來系統性能問題,例如頻繁的FullGC,以及多線程造成的上下文頻繁的切換,都會導致CPU繁忙,一般情況下CPU使用率<75%比較合適。 記憶體:Java記憶體一般是 ...
  • 我們智能客服知識庫機器人已經開發完成,後端資料庫是使用的qdrant向量資料庫,但是該資料庫並沒有導出備份功能,所以我按簡單的純前端實現知識庫導出excel數據 使用第三方庫(如SheetJS) SheetJS是一個流行的JavaScript庫,可幫助處理Excel文件。您可以使用SheetJS來將 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 愉快的雙休周末剛過完,早上來忽然被運營通知線上業務掛了,用戶無法下單。卧槽,趕緊進入debug模式,一查原來是服務端返回的數據有問題,趕緊問了服務端,大佬回覆說是業務部門配置套餐錯誤。好在主責不在我們,不過趕緊寫了復盤文檔,主動找自 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • 1.添加函數修改img的屬性; /** * * @param {*} idName 傳入的id,獲取改img的dom,添加相應的數學 */ export const proxyImg = (idName) => { const img = document.getElementById(idName ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...