成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

異步 JavaScript - 事件循環(huán)

tolerious / 1488人閱讀

摘要:創(chuàng)建全局上下文由表示,并將全局上下文推到棧頂。在了解異步執(zhí)行之前還需要知道一些概念,事件循環(huán)和回調(diào)隊(duì)列也稱為任務(wù)隊(duì)列或消息隊(duì)列。會(huì)等待事件循環(huán)調(diào)度。事件循環(huán)事件循環(huán)的作用是查看調(diào)用棧并確定調(diào)用棧是否空閑。

簡評(píng):如果你對(duì) JavaScript 異步的原理感興趣,這里有一篇不錯(cuò)的介紹。
JavaScript 同步代碼是如果工作的

在介紹 JavaScript 異步執(zhí)行之前先來了解一下, JavaScript 同步代碼是如何執(zhí)行的。

這里有兩個(gè)概念需要了解:

執(zhí)行上下文(Excution Context)

執(zhí)行上下文是一個(gè)抽象的概念,用于表示 JavaScript 的運(yùn)行環(huán)境,任何代碼都會(huì)有一個(gè)執(zhí)行上下文。

全局代碼運(yùn)行在全局執(zhí)行上下文,函數(shù)里的代碼運(yùn)行在函數(shù)執(zhí)行上下文,每一個(gè)函數(shù)都有自己的執(zhí)行上下文。

調(diào)用堆棧(Call Stack)

調(diào)用棧是一個(gè)具有 LIFO(后進(jìn)先出)結(jié)構(gòu)的棧,用于儲(chǔ)存代碼執(zhí)行階段所有的執(zhí)行上下文。

因?yàn)?JavaScript 是單線程的,所以 JavaScript 只有一個(gè)多帶帶的調(diào)用棧。

我們以下面例子介紹同步代碼執(zhí)行過程。

const second = () => {
  console.log("Hello there!");
}
const first = () => {
  console.log("Hi there!");
  second();
  console.log("The End");
}
first();

創(chuàng)建全局上下文(由 main() 表示),并將全局上下文推到棧頂。然后依次將遇到函數(shù)執(zhí)行上下文推到棧頂(如果函數(shù)中執(zhí)行其他他函數(shù),其他函數(shù)依次推到棧頂以此類推)。當(dāng)函數(shù)執(zhí)行完畢對(duì)應(yīng)的執(zhí)行上下文會(huì)從調(diào)用棧彈出,程序結(jié)束時(shí)全局上下文從調(diào)用棧彈出。

JavaScript 異步代碼是如何執(zhí)行的?

通過上個(gè)章節(jié)我們已經(jīng)對(duì)調(diào)用棧和 JavaScript 的同步執(zhí)行有了基本的了解,現(xiàn)在來看看 JavaScript 異步執(zhí)行是如何工作的。

什么是阻塞?

由于 JavaScript 是單線程的,如果某個(gè)函數(shù)耗費(fèi)的時(shí)間比較長,會(huì)阻塞后面的任務(wù)執(zhí)行,這就造成了阻塞。解決阻塞最簡單的方法是函數(shù)直接返回不等待,使用異步回調(diào)來處理返回結(jié)果。

在了解 JavaScript 異步執(zhí)行之前還需要知道一些概念,事件循環(huán)和回調(diào)隊(duì)列(也稱為任務(wù)隊(duì)列或消息隊(duì)列)。

注意:Event Loop 、Web APIs 和 Message Queue 并不是 JavaScript 引擎的一部分,而是瀏覽器運(yùn)行時(shí)環(huán)境和 Nodejs 運(yùn)行時(shí)環(huán)境的一部分。

我們以下面代碼為例,解釋異步代碼是如何執(zhí)行的。

const networkRequest =()=> { 
  setTimeout(()=> { 
    console.log("Async Code"); 
  },2000); 
};
console.log("Hello World");
networkRequest();
console.log("The End");

當(dāng)上述程序加載到瀏覽器時(shí) console.log(‘Hello World’) 代碼執(zhí)行時(shí)會(huì)一次在調(diào)用棧推入和彈出。遇到 networkRequest() 將其推入到調(diào)用棧頂。然后繼續(xù)將 networkRequest 內(nèi)的 setTimeout 方法推入棧頂,隨后 setTimeout networkRequest 依次出棧。最后對(duì) console.log(‘The End’) 進(jìn)行入棧出棧。

當(dāng) timer 到期后會(huì)將 callback 推入 message queue(消息隊(duì)列)中,此時(shí) callback 不會(huì)馬上執(zhí)行。會(huì)等待事件循環(huán)調(diào)度。

事件循環(huán)

事件循環(huán)的作用是查看調(diào)用棧并確定調(diào)用棧是否空閑。如果調(diào)用??臻e,even loop 會(huì)查看消息隊(duì)列是否有待處理的 callback 需要觸發(fā)。例子中的消息隊(duì)列只包含一個(gè) callback,當(dāng)調(diào)用棧為空的時(shí)候,even loop 會(huì)將 callback 推入調(diào)用棧中觸發(fā) networkRequest 的回調(diào)。

DOM 事件

消息隊(duì)列還會(huì)包含來自 DOM 的事件回調(diào),比如鼠標(biāo)和鍵盤事件回調(diào)。例如:

document.querySelector(".btn").addEventListener("click",function callback(event) {
  console.log("Button Clicked");
});

對(duì)于 DOM 事件,當(dāng)具體的事件觸發(fā)會(huì)將 callback 推入消息隊(duì)列中,等待 even loop 來調(diào)度執(zhí)行。

ES6 job queue/micro-task queue

ES6 新增了 job queue/micro-task queue 概念,在 Promise 中用到。job queue 比 message queue 擁有更高的優(yōu)先級(jí)。意味著 job queue 和 message queue 都有任務(wù)時(shí)會(huì)優(yōu)先執(zhí)行 job queue 中的任務(wù)。例如:

console.log("Script start");

// callback 在 message queue 中
setTimeout(function callback() {
  console.log("setTimeout");
}, 0);

// 任務(wù)在 micro-task queue 中
new Promise((resolve, reject) => {
    resolve("Promise resolved");
  }).then(res => console.log(res))
    .catch(err => console.log(err));
console.log("Script End");

// 輸出:
Script start
Script End
Promise resolved
setTimeout

再來看下一個(gè)例子(兩個(gè) setTimeout 和 兩個(gè) Promise):

console.log("Script start");
setTimeout(() => {
  console.log("setTimeout 1");
}, 0);
setTimeout(() => {
  console.log("setTimeout 2");
}, 0);
new Promise((resolve, reject) => {
    resolve("Promise 1 resolved");
  }).then(res => console.log(res))
    .catch(err => console.log(err));
new Promise((resolve, reject) => {
    resolve("Promise 2 resolved");
  }).then(res => console.log(res))
    .catch(err => console.log(err));
console.log("Script End");


//輸出為
Script start
Script End
Promise 1 resolved
Promise 2 resolved
setTimeout 1
setTimeout 2

由此可見 micro-task queue 中的所有任務(wù)都會(huì)優(yōu)先于 message queue 中的任務(wù)執(zhí)行。

原文:Understanding Asynchronous JavaScript?—?the Event Loop

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99753.html

相關(guān)文章

  • 總結(jié)javascript基礎(chǔ)概念(二):事件隊(duì)列循環(huán)

    摘要:而事件循環(huán)是主線程中執(zhí)行棧里的代碼執(zhí)行完畢之后,才開始執(zhí)行的。由此產(chǎn)生的異步事件執(zhí)行會(huì)作為任務(wù)隊(duì)列掛在當(dāng)前循環(huán)的末尾執(zhí)行。在下,觀察者基于監(jiān)聽事件的完成情況在下基于多線程創(chuàng)建。 主要問題: 1、JS引擎是單線程,如何完成事件循環(huán)的? 2、定時(shí)器函數(shù)為什么計(jì)時(shí)不準(zhǔn)確? 3、回調(diào)與異步,有什么聯(lián)系和不同? 4、ES6的事件循環(huán)有什么變化?Node中呢? 5、異步控制有什么難點(diǎn)?有什么解決方...

    zhkai 評(píng)論0 收藏0
  • JavaScript單線程事件循環(huán)(Event Loop)那些事

    摘要:概述本篇主要介紹的運(yùn)行機(jī)制單線程事件循環(huán)結(jié)論先在中利用運(yùn)行至完成和非阻塞完成單線程下異步任務(wù)的處理就是先處理主模塊主線程上的同步任務(wù)再處理異步任務(wù)異步任務(wù)使用事件循環(huán)機(jī)制完成調(diào)度涉及的內(nèi)容有單線程事件循環(huán)同步執(zhí)行異步執(zhí)行定時(shí)器的事件循環(huán)開始 1.概述 本篇主要介紹JavaScript的運(yùn)行機(jī)制:單線程事件循環(huán)(Event Loop). 結(jié)論先: 在JavaScript中, 利用運(yùn)行至...

    Shisui 評(píng)論0 收藏0
  • JavaScript 運(yùn)行機(jī)制詳解(理解同步、異步事件循環(huán))

    摘要:從異步過程的角度看,函數(shù)就是異步過程的發(fā)起函數(shù),事件監(jiān)聽函數(shù)就是異步過程的回調(diào)函數(shù)。事件觸發(fā)時(shí),表示異步任務(wù)完成,會(huì)將事件監(jiān)聽器函數(shù)封裝成一條消息放到消息隊(duì)列中,等待主線程執(zhí)行。 1.為什么JavaScript是單線程? JavaScript語言的一大特點(diǎn)就是單線程,也就是說,同一個(gè)時(shí)間只能做一件事。那么,為什么JavaScript不能有多個(gè)線程呢?這樣能提高效率啊。JavaScrip...

    loonggg 評(píng)論0 收藏0
  • (轉(zhuǎn))JavaScript:同步、異步事件循環(huán)

    摘要:事件循環(huán)事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息執(zhí)行的過程。事件觸發(fā)時(shí),表示異步任務(wù)完成,會(huì)將事件監(jiān)聽器函數(shù)封裝成一條消息放到消息隊(duì)列中,等待主線程執(zhí)行。 一. 單線程 我們常說JavaScript是單線程的。 所謂單線程,是指在JS引擎中負(fù)責(zé)解釋和執(zhí)行JavaScript代碼的線程只有一個(gè)。不妨叫它主線程。 但是實(shí)際上還存在其他的線程。例如:處理AJAX請(qǐng)求的線程、處理DOM事件的線...

    android_c 評(píng)論0 收藏0
  • JavaScript運(yùn)行機(jī)制和事件循環(huán)

    摘要:主線程不斷重復(fù)上面的三步,此過程也就是常說的事件循環(huán)。所以主線程代碼執(zhí)行時(shí)間過長,會(huì)阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機(jī)制任務(wù)隊(duì)列的順序機(jī)制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán) 1. 說明 讀過本文章后,您能知道: JavaScript代碼在瀏覽器中的執(zhí)行機(jī)制和事件循環(huán) 面試中經(jīng)常遇到的代碼輸出順序問題 首先通過一段代碼來驗(yàn)證你是否了解代碼輸出順序,如果你不知道輸出...

    Ververica 評(píng)論0 收藏0
  • 【筆記】 你不知道的JS讀書筆記——異步

    摘要:異步請(qǐng)求線程在在連接后是通過瀏覽器新開一個(gè)線程請(qǐng)求將檢測到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件循環(huán)隊(duì)列中。 基礎(chǔ):瀏覽器 -- 多進(jìn)程,每個(gè)tab頁獨(dú)立一個(gè)瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核) 每個(gè)瀏覽器渲染進(jìn)程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎) JS引擎線程負(fù)...

    junnplus 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<