高級前端進階(五)

来源:https://www.cnblogs.com/ywjbokeyuan/archive/2022/05/09/16011512.html
-Advertisement-
Play Games

詳解JavaScript中的事件迴圈機制!!! 一、簡單講解 這個大家應該或多或少都知道的 for (var i = 0; i < 10; i++) { setTimeout(() => { console.log(i); // 輸出10個10 }); } 解析:先執行for迴圈,迴圈疊加i,然後再 ...


詳解JavaScript中的事件迴圈機制!!!

一、簡單講解

這個大家應該或多或少都知道的

for (var i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i); // 輸出10個10
  });
}

解析:先執行for迴圈,迴圈疊加i,然後再執行setTimeout 10遍,所以會輸出10個10
變體:

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i); // 依次輸出0-9
  });
}

我們知道var跟let本質區別就是作用域的問題,所以會聯想到let導致的,但在這一點上,並不是作用域問題,因為從事件迴圈機制來解釋是有問題的
以上的代碼等價於

for (var i = 0; i < 10; i++) {
  (function (i) {
    setTimeout(() => {
      console.log(i);
    });
  })(i); // 立即執行函數,以上的let應該是將代碼特殊處理了下
}

立即執行函數:函數聲明後立即執行。
從事件迴圈的角度來說,應該先執行for迴圈將i疊加到10,執行完後再去執行for迴圈體(setTimeout),此時的i變成了10,所以每次輸出都是10,
這裡使用let,應該是特殊處理了一下的。

二、深入講解

我們知道JavaScript語言是單線程的,至於為啥是單線程?
假設有兩個線程,一個在頁面上新增一個div,另一個線程在頁面上刪除div,那最終聽誰的?
那JavaScript怎麼實現非同步的呢?
在JavaScript中,有兩類任務:同步任務和非同步任務。
同步任務:普通的任務,依次從上往下執行。
非同步任務:又分為巨集任務、微任務。

巨集任務:setTimeout跟setInterval
微任務:Promise().then() 這裡要註意一下,Promise方法裡面的是同步任務,then裡面的才是微任務
執行順序:先執行同步任務,遇到非同步任務,將其放入到巨集任務或者微任務隊列中,然後優先執行微任務,接下來再去執行巨集任務。

簡單的例子:

setTimeout(function() {
    console.log(1)
}, 0);

new Promise(function(resolve, reject) {
    console.log(2); // 這裡是同步任務
    resolve();
}).then((res) => {
    console.log(3);
})
console.log(4);
// 輸出結果是 2  4  3  1

解析:從上往下執行,setTimeout是巨集任務,放到巨集任務隊列中,
Promise裡面的是同步任務,所以先執行,輸出2,then裡面的是微任務,放到微任務隊列中,
最後一個是同步任務,執行,輸出4,
然後執行微任務,輸出3
最後執行巨集任務,輸出1

來點難度的:

console.log(1);

setTimeout(function () {
  console.log(2);
}, 0);

setTimeout(function () {
  console.log(3);

  setTimeout(function () {
    console.log(4);
  }, 0);
}, 0);

new Promise(function (resolve, reject) {
  console.log(5);
  resolve();
}).then((res) => {
  console.log(6);
  new Promise(function (resolve, reject) {
    console.log(7);
    resolve();
  }).then((res) => {
    console.log(8);
  });
});

new Promise(function (resolve, reject) {
  console.log(9);
  resolve();
})
  .then((res) => {
    console.log(10);
  })
  .then((res) => {
    console.log(11);
  });

console.log(12);
// 輸出 1  5   9   12
//      6  7  10   8   11
//      2  3  4

解析:原理跟上面一樣,不過需要註意的是,8跟11的順序:,在這裡then的層級,將各個Promise裡面第一層的then放在一起,第二層的then放在一起,依此類推,
然後依次執行第一層的,執行完第一層,接下來執行完第二層,依此類推。
第一層(6,7,10)
第二層(8,11)
所以先輸出8, 再輸出11的。

再來一個(也最可能出錯或者無法理解的):

console.log(1);
async function fn() {
  console.log(2);
  await console.log(3);
  console.log(4); // 這一步,你應該會有問題
}
setTimeout(() => {
  console.log(5);
}, 0);
fn();
new Promise((resolve) => {
  console.log(6);
  resolve();
}).then(() => {
  console.log(7);
});
console.log(8);
// 輸出:1  2  3   6   8   4  7  5

解析:async await是Promise的語法糖,只是針對寫法上的優化
將async await翻譯成Promise:

async function fn() {
  console.log(2);
  await console.log(3);
  console.log(4); // 這一步,你應該會有問題
}
// 等價於
function fn() {
  return new Promise((resolve, reject) => {
    console.log(2);
    resolve(
      (() => {
        console.log(3);
      })() // 立即執行函數
    );
  }).then(() => {
    console.log(4);
  });
}

這樣,你應該能夠明白,為啥輸出3之後不是立即輸出4了吧!

再來一道加深鞏固的:

console.log(1);
async function fn() {
  console.log(2);
  await console.log(3);
  await console.log(4);
  console.log(5);
}
setTimeout(() => {
  console.log(6);
}, 2000);
setTimeout(() => {
  console.log(7);
}, 1000);
fn();
new Promise((resolve) => {
  console.log(8);
  new Promise((resolve) => {
    console.log(9);
    resolve();
  }).then(() => {
    console.log(10);
  });
  resolve();
}).then(() => {
  console.log(11);
  new Promise((resolve) => {
    console.log(12);
    resolve();
  }).then(() => {
    console.log(13);
  });
});
console.log(14);
// 輸出 1  2  3  8  9  14
//      4  10 11 12 5  13
//      7  6 

我相信,你現在應該理解掌握了!

只要鑽的深,鐵杵都能給你磨成針!!!

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

-Advertisement-
Play Games
更多相關文章
  • SQL語言基礎 SQL (Structured Query Language:結構化查詢語言) 是用於管理關係資料庫管理系統(RDBMS)。 SQL 的範圍包括數據插入、查詢、更新和刪除,資料庫模式創建和修改,以及數據訪問控制。 本文主要記錄一些主要的SQL命令(比如 SELECT、UPDATE、D ...
  • 一、使用PIVOT實現行轉列 1、首先創建一個學生表 CREATE TABLE [dbo].[Students]( [stu_id] [int] IDENTITY(1,1) NOT NULL, [stu_name] [varchar](100) NULL, [stu_hobby] [varchar] ...
  • 在進行視頻通話過程中,用戶有時候會出現網路不好的情況,比如在進行多人視頻通話或者多人唱歌時,我們需要實時顯示用戶的網路質量。 ...
  • 本次上新,共計新增94個開源組件。組件涉及工具、網路、UI、圖形、音視頻等多種功能。 ...
  • 5月11日晚19:00,Hello HarmonyOS進階系列應用篇第二課《電腦視覺》直播如約而至。 ...
  • 隨著新技術的不斷演進,人工智慧已經廣泛地應用到教育、金融、物流、零售、交通、醫療等各個領域。而在AI高速發展的當下,高效開發變得更為重要,如何將創意想法與AI技術深度融合,迅速轉化為可落地的AI應用,是開發者在激烈競爭中制勝的關鍵。 為了助力開發者快速上線AI業務,為消費者提供創新AI體驗,HMS ...
  • 只有在ajax才能找回一點點主場了,vue中的ajax一天整完,內容還行,主要是對axios的運用。 明天按理說要開始vuex了,這個從來都是只耳聞沒有眼見過,明天來看看看看是個什麼神奇的東西。 一. 解決開發環境ajax跨域問題 1.配置代理(方法一) 首先我們能發起ajax請求的,xhr原生不推 ...
  • 大家好,我是半夏👴,一個剛剛開始寫文的沙雕程式員.如果喜歡我的文章,可以關註➕ 點贊 👍 加我微信:frontendpicker,一起學習交流前端,成為更優秀的工程師~關註公眾號:搞前端的半夏,瞭解更多前端知識! 點我探索新世界! 原文鏈接 ==>http://sylblog.xin/archi ...
一周排行
    -Advertisement-
    Play Games
  • 就像 Web Api 介面可以對入參進行驗證,避免用戶傳入非法的或者不符合我們預期的參數一樣,選項也可以對配置源的內容進行驗證,避免配置中的值與選項類中的屬性不對應或者不滿足預期,畢竟大部分配置都是通過字元串的方式,驗證是很有必要的。 1. 註解驗證 像入參驗證一樣,選項驗證也可以通過特性註解方便地 ...
  • 原文作者:aircraft 原文鏈接:https://www.cnblogs.com/DOMLX/p/17270107.html 加工的泛型類如下: using System; using System.Collections.Generic; using System.IO; using Syst ...
  • 在前一篇文章,我們瞭解瞭如何通過.NET6+Quartz開發基於控制台應用程式的定時任務,今天繼續在之前的基礎上,進一步講解基於ASP.NET Core MVC+Quartz實現定時任務的可視化管理頁面,僅供學習分享使用,如有不足之處,還請指正。 涉及知識點 Quartz組件,關於Quartz組件的 ...
  • 面向對象1 面向對象,更在乎的結果,而過程的實現並不重要 IDea快捷鍵(基礎版) | 快捷鍵 | 作用 | | | | | ctrl + / | 快捷註釋 | | ctrl + shift + / | 多行註釋 | | ctrl + d | 快速複製 | | ctrl + shift + up/d ...
  • NX中的checkmate功能是用於檢查模型、圖紙數據的工具,在UGOPEN中有例子。手動操作可以檢查已載入的裝配下所有零部件,可以設置通過後保存模型,檢查結果保存到Teamcenter中,預設保存在零組件版本下。 代碼中可以設置多個檢查規則。相關設置可以在用戶預設設置中進行設置。 1 // 2 / ...
  • JavaSE 運算符 算術運算符:+,-,*,/,%,++(自增),--(自減) i++:先用後+1;++i:先+1後用 賦值運算符:= 擴展賦值運算符:+=,-=,*=,/= a+=b >a=a+b: ​ 可讀性差,但是編譯效率高,且會自動進行類型轉換; ​ 當ab為基本數據類型時,a+b和b+a ...
  • 面向對象2 訪問修飾符 | | private | default | protected | public | | | | | | | | 當前類 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_che ...
  • 推薦一些學習qml教程 Qt官方的QML教程: https://doc.qt.io/qt-5/qtqml-index.html 這是一個由Qt官方提供的完整的QML教程,包含了所有基本知識和高級語法。 QML中文網:http://www.qmlcn.com/ 這是一個非常不錯的中文QML學習網站,提 ...
  • QAbstractBUtton: 所有按鈕控制項的基類 提供按鈕的通用功能 繼承自QWidget 屬於抽象類別,不能直接去使用,必須藉助於子類(除非你覺得子類不夠用,想自定義一個按鈕) 大部分功能之前已經使用過,在這裡只作簡單介紹 文本設置: setText(str) :設置按鈕提示文本 text() ...
  • 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹 VLD 配置文件中配置項 StartDisabled 的使用方法。 ...