JS事件迴圈機制(面試快速解題技巧)

来源:https://www.cnblogs.com/chscript/archive/2023/01/15/16994963.html
-Advertisement-
Play Games

事件迴圈機制 同步與非同步 我們先思考兩個問題,如下: 為什麼會存在同步和非同步的概念? 我們的JavaScript是單線程的,也就是我們的工作流水線的只有一條。如果我們的任務全放在流水線上,其中一個任務出現問題就會阻塞後面的任務,導致我們的工作流水線卡住。因此為了更加高效合理利用這條流水線,在Java ...


目錄

事件迴圈機制

同步與非同步

我們先思考兩個問題,如下:

為什麼會存在同步和非同步的概念?

我們的JavaScript是單線程的,也就是我們的工作流水線的只有一條。如果我們的任務全放在流水線上,其中一個任務出現問題就會阻塞後面的任務,導致我們的工作流水線卡住。因此為了更加高效合理利用這條流水線,在JavaScript中出現了同步與非同步的概念。

同步與非同步任務如何在一條流水線上工作?

同樣是一條流水線。我們的有不同的產品,有的產品能瞬間完成,有的產品需要耗費大量時間才能完成。那麼我們給這堆產品分為兩類,能瞬間完成的產品先放入流水線前面,而需要耗費大量時間的產品則放在流水線後面。將所有的產品按順序從流水線上執行。即使後面有部分產品製作很慢,但我們流水線前面的大部分產品都能順利完成。也就是說,我們能夠及時交付大部分的產品,讓老闆基本滿意就足夠了。後面的產品我們再慢慢做也不遲。

同步

同步任務:我們的任務不會造成流水線阻塞,瞬間就能完成。那我們直接把這些任務定義為同步任務。

同步事件:new Promise()、async關鍵字、console對象方法

非同步

非同步任務:我們的任務可能會造成流水線阻塞,需要時間才能完成。那我們直接把這些任務定義為非同步任務。

非同步事件:我們先不介紹非同步事件,因為非同步事件又分為微任務與巨集任務。我們下麵再介紹。

微任務與巨集任務(非同步事件)

微任務事件:Promise.then()、await 後面的語句、queueMiscrotask、MutationObserver、process.nextTick( node.js環境 )[ 微任務中最先執行 ]

巨集任務事件:setTimout() 和 setInterval()、<script>腳本、I/O、UI交互事件、setImmediate( node.js環境 )[ 巨集任務中最後執行 ]

註意:非同步事件分為微任務和巨集任務,其中微任務優先於巨集任務執行。

任務執行順序

執行棧:同步代碼會首先歸類到此處待執行。按照代碼的書寫順序(上到下)入棧。

微任務隊列:非同步中的微任務代碼歸類到此處。按照代碼的書寫順序(上到下)入隊。當執行棧為空時,微任務會出隊進入執行棧

巨集任務隊列:非同步中的巨集任務代碼歸類到此處。按照代碼的書寫順序(上到下)入隊。當微任務隊列為空時,巨集任務會出隊進入執行棧

我們採用驗證法做幾道題

第一道如下

console.log(1)
setTimeout(() => {
    console.log(2)
    setTimeout(() => {
        console.log(3)
    }, 1000)
}, 1000)
new Promise((resolve, reject) => {
    console.log(4)
    resolve(5) // 之後會調用 then 方法
    console.log(6)
}).then((resolve, reject) => {
    console.log(resolve)
})
function add(a, b) {
    return a + b
}
async function foo() {
    console.log(7)
    let num = await add(4, 4)
    console.log(9)
    return num
}
foo().then((num) => {
    console.log(num)
})
console.log(10) // 1 4 6 7 10 5 9 8 2 3

以上代碼沒有出現巨集任務嵌套微任務,微任務嵌套巨集任務的情況。那麼我們可以按編號(對應的輸出語句)直接對執行棧、微任務和巨集任務分類如下:

第一次分析執行棧(同步任務):1 4 6 7 10

第二次分析微任務:5 9 8

第三次分析巨集任務:2 3

然後我們按執行順序將答案組合在一起。最終答案:1 4 6 7 10 5 9 8 2 3。

註意:以上分析方法只能應對非同步函數無嵌套的情況。

接下來我們增加難度,巨集任務嵌套微任務,微任務嵌套巨集任務第二題如下

console.log(1)
setTimeout(() => {
    console.log(2)
    new Promise((resolve, reject) => {
        console.log(3)
      	resolve(4)
    }).then((resolve, reject) => {
        console.log(resolve)
    })
  	console.log(5)
}, 1000)
console.log(6)
new Promise((resolve, reject) => {
    console.log(7)
    resolve(8)
    setTimeout(() => {
        console.log(9)
    }, 1000)
}).then((resolve, reject) => {
    console.log(resolve)
})
console.log(10) // 1 6 7 10 8 2 3 5 4 9

以上代碼出現了巨集任務嵌套微任務,微任務嵌套巨集任務的情況。

提示:外部(全局作用域)的代碼可以按任務執行順序分析,非同步函數內部其實也可以按照我們的任務執行順序分析。其分析過程是一樣的。

最終答案:1 6 7 10 8 2 3 5 4 9。還有很多特例,可自行編寫非同步函數測試。總結方法

最終總結

分析方法:先對代碼進行事件分類,然後分別放入對應類型的三個地方(執行棧、微任務隊列和巨集任務隊列)再按照我們的執行順序,發生非同步函數嵌套情況時,也可以對其內部應用這套規則解決。

任務執行順序如下

  1. 同步(new Promise()、async關鍵字、console對象方法)
  2. process.nextTick(node.js環境)
  3. 微任務(非同步)(Promise().then()、await 後面的語句)
  4. 巨集任務(非同步)(定時器函數、<script>腳本、I/O、UI交互事件)
  5. setImmediate(node.js環境)(當前事件迴圈結束後執行)

參考

【前端八股文】事件迴圈-巨集任務和微任務


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

-Advertisement-
Play Games
更多相關文章
  • 作者:Hai Xiang 來源:https://www.cnblogs.com/haixiang/p/12867160.html 什麼是elasticsearch Elasticsearch 是一個開源的高度可擴展的全文搜索和分析引擎,擁有查詢近實時的超強性能。 大名鼎鼎的Lucene 搜索引擎被廣 ...
  • 1 簡介 GKE(Google Kubernetes Engine)是一個K8s平臺, 我們可以使用gcloud來創建GKE集群。在開始之前,可以查看:《初始化一個GCP項目並用gcloud訪問操作》。 2 創建GKE集群 2.1 打開API 在創建集群之前,需要打開Google API,不然無法操 ...
  • 前言 眾所周知記憶體緩存(MemoryCache)數據是從記憶體中獲取,性能表現上是最優的,但是記憶體緩存有一個缺點就是不支持分散式,數據在各個部署節點上各存一份,每份緩存的過期時間不一致,會導致幻讀等各種問題,所以我們實現分散式緩存通常會用上Redis 但如果在高併發的情況下讀取Redis的緩存,會進行 ...
  • 一般一個人的成長是分幾個階段的,具體如下: 1)剛開始參與開發階段:這個階段基礎不是很好,一邊學基礎,一邊做開發,剛開始的時候大家都是這樣,如果想快速的跳過這個階段,工具書與筆記(自己做的那種)就是速成方法了。大家一定要多辛苦敲代碼。 2)菜鳥階段:所謂菜鳥就是會做資料庫增刪改查,一般到了這個階段就 ...
  • 痞子衡嵌入式半月刊: 第 70 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 ...
  • 如同 STM32F103C8T6 與 CBT6 有著同樣的128K flash容量一樣, 市面上很多晶元, 同一系列的多個型號其實底下使用的是相同的硬體, 只是通過軟體, 晶元ID, 某些隱藏寄存器(例如AIR32F103)或者物理熔斷對容量進行限制. 讓我們看一看 PY32F002AF15P 這顆... ...
  • 列表中自動播放視頻,常規方案是在每個 xml 中寫入視頻佈局,然後在滑動時獲取當前的下標,播放此下標的視頻 弊端:播放容易出錯,需要精準控制好停止播放操作,並且適配器中容易觸發多次刷新,導致執行多次同樣的操作,不易控制離開停止等操作,增加了佈局的負擔,影響滑動流暢度,無法復用... 使用過的都比較清 ...
  • 按鈕: <el-button id="manyou" @click="Ismovement" type="primary" >漫游模式</el-button> 樣式: /* 逗號表示A,B兩個標簽同時擁有大括弧中的CSS樣式 */ .el-button--primary.is-active, /* ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...