国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

瀏覽器與Node的事件循環(huán)(Event Loop)有何區(qū)別?

TANKING / 732人閱讀

摘要:事件觸發(fā)線程主要負(fù)責(zé)將準(zhǔn)備好的事件交給引擎線程執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。

Fundebug經(jīng)作者浪里行舟授權(quán)首發(fā),未經(jīng)同意請勿轉(zhuǎn)載。

前言

本文我們將會介紹 JS 實(shí)現(xiàn)異步的原理,并且了解了在瀏覽器和 Node 中 Event Loop 其實(shí)是不相同的。

一、線程與進(jìn)程 1. 概念

我們經(jīng)常說 JS 是單線程執(zhí)行的,指的是一個進(jìn)程里只有一個主線程,那到底什么是線程?什么是進(jìn)程?

官方的說法是:進(jìn)程是 CPU 資源分配的最小單位;線程是 CPU 調(diào)度的最小單位。這兩句話并不好理解,我們先來看張圖:

進(jìn)程好比圖中的工廠,有多帶帶的專屬自己的工廠資源。

線程好比圖中的工人,多個工人在一個工廠中協(xié)作工作,工廠與工人是 1:n 的關(guān)系。也就是說一個進(jìn)程由一個或多個線程組成,線程是一個進(jìn)程中代碼的不同執(zhí)行路線

工廠的空間是工人們共享的,這象征一個進(jìn)程的內(nèi)存空間是共享的,每個線程都可用這些共享內(nèi)存

多個工廠之間獨(dú)立存在。

2. 多進(jìn)程與多線程

多進(jìn)程:在同一個時間里,同一個計算機(jī)系統(tǒng)中如果允許兩個或兩個以上的進(jìn)程處于運(yùn)行狀態(tài)。多進(jìn)程帶來的好處是明顯的,比如你可以聽歌的同時,打開編輯器敲代碼,編輯器和聽歌軟件的進(jìn)程之間絲毫不會相互干擾。

多線程:程序中包含多個執(zhí)行流,即在一個程序中可以同時運(yùn)行多個不同的線程來執(zhí)行不同的任務(wù),也就是說允許單個程序創(chuàng)建多個并行執(zhí)行的線程來完成各自的任務(wù)。

以 Chrome 瀏覽器中為例,當(dāng)你打開一個 Tab 頁時,其實(shí)就是創(chuàng)建了一個進(jìn)程,一個進(jìn)程中可以有多個線程(下文會詳細(xì)介紹),比如渲染線程、JS 引擎線程、HTTP 請求線程等等。當(dāng)你發(fā)起一個請求時,其實(shí)就是創(chuàng)建了一個線程,當(dāng)請求結(jié)束后,該線程可能就會被銷毀。

二、瀏覽器內(nèi)核

簡單來說瀏覽器內(nèi)核是通過取得頁面內(nèi)容、整理信息(應(yīng)用 CSS)、計算和組合最終輸出可視化的圖像結(jié)果,通常也被稱為渲染引擎。

瀏覽器內(nèi)核是多線程,在內(nèi)核控制下各線程相互配合以保持同步,一個瀏覽器通常由以下常駐線程組成:

GUI 渲染線程

JavaScript 引擎線程

定時觸發(fā)器線程

事件觸發(fā)線程

異步 http 請求線程

1. GUI 渲染線程

主要負(fù)責(zé)頁面的渲染,解析 HTML、CSS,構(gòu)建 DOM 樹,布局和繪制等。

當(dāng)界面需要重繪或者由于某種操作引發(fā)回流時,將執(zhí)行該線程。

該線程與 JS 引擎線程互斥,當(dāng)執(zhí)行 JS 引擎線程時,GUI 渲染會被掛起,當(dāng)任務(wù)隊列空閑時,JS 引擎才會去執(zhí)行 GUI 渲染。

2. JS 引擎線程

該線程當(dāng)然是主要負(fù)責(zé)處理 JavaScript 腳本,執(zhí)行代碼。

也是主要負(fù)責(zé)執(zhí)行準(zhǔn)備好待執(zhí)行的事件,即定時器計數(shù)結(jié)束,或者異步請求成功并正確返回時,將依次進(jìn)入任務(wù)隊列,等待 JS 引擎線程的執(zhí)行。

當(dāng)然,該線程與 GUI 渲染線程互斥,當(dāng) JS 引擎線程執(zhí)行 JavaScript 腳本時間過長,將導(dǎo)致頁面渲染的阻塞。

3. 定時器觸發(fā)線程

負(fù)責(zé)執(zhí)行異步定時器一類的函數(shù)的線程,如: setTimeout,setInterval。

主線程依次執(zhí)行代碼時,遇到定時器,會將定時器交給該線程處理,當(dāng)計數(shù)完畢后,事件觸發(fā)線程會將計數(shù)完畢后的事件加入到任務(wù)隊列的尾部,等待 JS 引擎線程執(zhí)行。

4. 事件觸發(fā)線程

主要負(fù)責(zé)將準(zhǔn)備好的事件交給 JS 引擎線程執(zhí)行。

比如 setTimeout 定時器計數(shù)結(jié)束, ajax 等異步請求成功并觸發(fā)回調(diào)函數(shù),或者用戶觸發(fā)點(diǎn)擊事件時,該線程會將整裝待發(fā)的事件依次加入到任務(wù)隊列的隊尾,等待 JS 引擎線程的執(zhí)行。

5. 異步 http 請求線程

負(fù)責(zé)執(zhí)行異步請求一類的函數(shù)的線程,如: Promise,axios,ajax 等。

主線程依次執(zhí)行代碼時,遇到異步請求,會將函數(shù)交給該線程處理,當(dāng)監(jiān)聽到狀態(tài)碼變更,如果有回調(diào)函數(shù),事件觸發(fā)線程會將回調(diào)函數(shù)加入到任務(wù)隊列的尾部,等待 JS 引擎線程執(zhí)行。

三、瀏覽器中的 Event Loop 1. Micro-Task 與 Macro-Task

事件循環(huán)中的異步隊列有兩種:macro(宏任務(wù))隊列和 micro(微任務(wù))隊列。宏任務(wù)隊列可以有多個,微任務(wù)隊列只有一個

常見的 macro-task 比如:setTimeout、setInterval、 setImmediate、script(整體代碼)、 I/O 操作、UI 渲染等。

常見的 micro-task 比如: process.nextTick、new Promise().then(回調(diào))、MutationObserver(html5 新特性) 等。

2. Event Loop 過程解析

一個完整的 Event Loop 過程,可以概括為以下階段:

一開始執(zhí)行棧空,我們可以把執(zhí)行棧認(rèn)為是一個存儲函數(shù)調(diào)用的棧結(jié)構(gòu),遵循先進(jìn)后出的原則。micro 隊列空,macro 隊列里有且只有一個 script 腳本(整體代碼)。

全局上下文(script 標(biāo)簽)被推入執(zhí)行棧,同步代碼執(zhí)行。在執(zhí)行的過程中,會判斷是同步任務(wù)還是異步任務(wù),通過對一些接口的調(diào)用,可以產(chǎn)生新的 macro-task 與 micro-task,它們會分別被推入各自的任務(wù)隊列里。同步代碼執(zhí)行完了,script 腳本會被移出 macro 隊列,這個過程本質(zhì)上是隊列的 macro-task 的執(zhí)行和出隊的過程。

上一步我們出隊的是一個 macro-task,這一步我們處理的是 micro-task。但需要注意的是:當(dāng) macro-task 出隊時,任務(wù)是一個一個執(zhí)行的;而 micro-task 出隊時,任務(wù)是一隊一隊執(zhí)行的。因此,我們處理 micro 隊列這一步,會逐個執(zhí)行隊列中的任務(wù)并把它出隊,直到隊列被清空。

執(zhí)行渲染操作,更新界面

檢查是否存在 Web worker 任務(wù),如果有,則對其進(jìn)行處理

上述過程循環(huán)往復(fù),直到兩個隊列都清空

我們總結(jié)一下,每一次循環(huán)都是一個這樣的過程:

當(dāng)某個宏任務(wù)執(zhí)行完后,會查看是否有微任務(wù)隊列。如果有,先執(zhí)行微任務(wù)隊列中的所有任務(wù),如果沒有,會讀取宏任務(wù)隊列中排在最前的任務(wù),執(zhí)行宏任務(wù)的過程中,遇到微任務(wù),依次加入微任務(wù)隊列。棧空后,再次讀取微任務(wù)隊列里的任務(wù),依次類推。

接下來我們看道例子來介紹上面流程:

Promise.resolve().then(()=>{
  console.log("Promise1")
  setTimeout(()=>{
    console.log("setTimeout2")
  },0)
})
setTimeout(()=>{
  console.log("setTimeout1")
  Promise.resolve().then(()=>{
    console.log("Promise2")
  })
},0)

最后輸出結(jié)果是 Promise1,setTimeout1,Promise2,setTimeout2

一開始執(zhí)行棧的同步任務(wù)(這屬于宏任務(wù))執(zhí)行完畢,會去查看是否有微任務(wù)隊列,上題中存在(有且只有一個),然后執(zhí)行微任務(wù)隊列中的所有任務(wù)輸出 Promise1,同時會生成一個宏任務(wù) setTimeout2

然后去查看宏任務(wù)隊列,宏任務(wù) setTimeout1 在 setTimeout2 之前,先執(zhí)行宏任務(wù) setTimeout1,輸出 setTimeout1

在執(zhí)行宏任務(wù) setTimeout1 時會生成微任務(wù) Promise2 ,放入微任務(wù)隊列中,接著先去清空微任務(wù)隊列中的所有任務(wù),輸出 Promise2

清空完微任務(wù)隊列中的所有任務(wù)后,就又會去宏任務(wù)隊列取一個,這回執(zhí)行的是 setTimeout2

四、Node 中的 Event Loop 1. Node 簡介

Node 中的 Event Loop 和瀏覽器中的是完全不相同的東西。Node.js 采用 V8 作為 js 的解析引擎,而 I/O 處理方面使用了自己設(shè)計的 libuv,libuv 是一個基于事件驅(qū)動的跨平臺抽象層,封裝了不同操作系統(tǒng)一些底層特性,對外提供統(tǒng)一的 API,事件循環(huán)機(jī)制也是它里面的實(shí)現(xiàn)(下文會詳細(xì)介紹)。

Node.js 的運(yùn)行機(jī)制如下:

V8 引擎解析 JavaScript 腳本。

解析后的代碼,調(diào)用 Node API。

libuv 庫負(fù)責(zé) Node API 的執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個 Event Loop(事件循環(huán)),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給 V8 引擎。

V8 引擎再將結(jié)果返回給用戶。

2. 六個階段

其中 libuv 引擎中的事件循環(huán)分為 6 個階段,它們會按照順序反復(fù)運(yùn)行。每當(dāng)進(jìn)入某一個階段的時候,都會從對應(yīng)的回調(diào)隊列中取出函數(shù)去執(zhí)行。當(dāng)隊列為空或者執(zhí)行的回調(diào)函數(shù)數(shù)量到達(dá)系統(tǒng)設(shè)定的閾值,就會進(jìn)入下一階段。

從上圖中,大致看出 node 中的事件循環(huán)的順序:

外部輸入數(shù)據(jù)-->輪詢階段(poll)-->檢查階段(check)-->關(guān)閉事件回調(diào)階段(close callback)-->定時器檢測階段(timer)-->I/O 事件回調(diào)階段(I/O callbacks)-->閑置階段(idle, prepare)-->輪詢階段(按照該順序反復(fù)運(yùn)行)...

timers 階段:這個階段執(zhí)行 timer(setTimeout、setInterval)的回調(diào)

I/O callbacks 階段:處理一些上一輪循環(huán)中的少數(shù)未執(zhí)行的 I/O 回調(diào)

idle, prepare 階段:僅 node 內(nèi)部使用

poll 階段:獲取新的 I/O 事件, 適當(dāng)?shù)臈l件下 node 將阻塞在這里

check 階段:執(zhí)行 setImmediate() 的回調(diào)

close callbacks 階段:執(zhí)行 socket 的 close 事件回調(diào)

注意:上面六個階段都不包括 process.nextTick()(下文會介紹)

接下去我們詳細(xì)介紹timerspollcheck這 3 個階段,因?yàn)槿粘i_發(fā)中的絕大部分異步任務(wù)都是在這 3 個階段處理的。

(1) timer

timers 階段會執(zhí)行 setTimeout 和 setInterval 回調(diào),并且是由 poll 階段控制的。
同樣,在 Node 中定時器指定的時間也不是準(zhǔn)確時間,只能是盡快執(zhí)行

(2) poll

poll 是一個至關(guān)重要的階段,這一階段中,系統(tǒng)會做兩件事情

回到 timer 階段執(zhí)行回調(diào)

執(zhí)行 I/O 回調(diào)

并且在進(jìn)入該階段時如果沒有設(shè)定了 timer 的話,會發(fā)生以下兩件事情

如果 poll 隊列不為空,會遍歷回調(diào)隊列并同步執(zhí)行,直到隊列為空或者達(dá)到系統(tǒng)限制

如果 poll 隊列為空時,會有兩件事發(fā)生

如果有 setImmediate 回調(diào)需要執(zhí)行,poll 階段會停止并且進(jìn)入到 check 階段執(zhí)行回調(diào)

如果沒有 setImmediate 回調(diào)需要執(zhí)行,會等待回調(diào)被加入到隊列中并立即執(zhí)行回調(diào),這里同樣會有個超時時間設(shè)置防止一直等待下去

當(dāng)然設(shè)定了 timer 的話且 poll 隊列為空,則會判斷是否有 timer 超時,如果有的話會回到 timer 階段執(zhí)行回調(diào)。

(3) check 階段

setImmediate()的回調(diào)會被加入 check 隊列中,從 event loop 的階段圖可以知道,check 階段的執(zhí)行順序在 poll 階段之后。

我們先來看個例子:

console.log("start")
setTimeout(() => {
  console.log("timer1")
  Promise.resolve().then(function() {
    console.log("promise1")
  })
}, 0)
setTimeout(() => {
  console.log("timer2")
  Promise.resolve().then(function() {
    console.log("promise2")
  })
}, 0)
Promise.resolve().then(function() {
  console.log("promise3")
})
console.log("end")
//start=>end=>promise3=>timer1=>timer2=>promise1=>promise2

一開始執(zhí)行棧的同步任務(wù)(這屬于宏任務(wù))執(zhí)行完畢后(依次打印出 start end,并將 2 個 timer 依次放入 timer 隊列),會先去執(zhí)行微任務(wù)(這點(diǎn)跟瀏覽器端的一樣),所以打印出 promise3

然后進(jìn)入 timers 階段,執(zhí)行 timer1 的回調(diào)函數(shù),打印 timer1,并將 promise.then 回調(diào)放入 microtask 隊列,同樣的步驟執(zhí)行 timer2,打印 timer2;這點(diǎn)跟瀏覽器端相差比較大,timers 階段有幾個 setTimeout/setInterval 都會依次執(zhí)行,并不像瀏覽器端,每執(zhí)行一個宏任務(wù)后就去執(zhí)行一個微任務(wù)(關(guān)于 Node 與瀏覽器的 Event Loop 差異,下文還會詳細(xì)介紹)。

3. 注意點(diǎn)

(1) setTimeout 和 setImmediate

二者非常相似,區(qū)別主要在于調(diào)用時機(jī)不同。

setImmediate 設(shè)計在 poll 階段完成時執(zhí)行,即 check 階段;

setTimeout 設(shè)計在 poll 階段為空閑時,且設(shè)定時間到達(dá)后執(zhí)行,但它在 timer 階段執(zhí)行

setTimeout(function timeout () {
  console.log("timeout");
},0);
setImmediate(function immediate () {
  console.log("immediate");
});

對于以上代碼來說,setTimeout 可能執(zhí)行在前,也可能執(zhí)行在后。

首先 setTimeout(fn, 0) === setTimeout(fn, 1),這是由源碼決定的
進(jìn)入事件循環(huán)也是需要成本的,如果在準(zhǔn)備時候花費(fèi)了大于 1ms 的時間,那么在 timer 階段就會直接執(zhí)行 setTimeout 回調(diào)

如果準(zhǔn)備時間花費(fèi)小于 1ms,那么就是 setImmediate 回調(diào)先執(zhí)行了

但當(dāng)二者在異步 i/o callback 內(nèi)部調(diào)用時,總是先執(zhí)行 setImmediate,再執(zhí)行 setTimeout

const fs = require("fs")
fs.readFile(__filename, () => {
    setTimeout(() => {
        console.log("timeout");
    }, 0)
    setImmediate(() => {
        console.log("immediate")
    })
})
// immediate
// timeout

在上述代碼中,setImmediate 永遠(yuǎn)先執(zhí)行。因?yàn)閮蓚€代碼寫在 IO 回調(diào)中,IO 回調(diào)是在 poll 階段執(zhí)行,當(dāng)回調(diào)執(zhí)行完畢后隊列為空,發(fā)現(xiàn)存在 setImmediate 回調(diào),所以就直接跳轉(zhuǎn)到 check 階段去執(zhí)行回調(diào)了。

(2) process.nextTick

這個函數(shù)其實(shí)是獨(dú)立于 Event Loop 之外的,它有一個自己的隊列,當(dāng)每個階段完成后,如果存在 nextTick 隊列,就會清空隊列中的所有回調(diào)函數(shù),并且優(yōu)先于其他 microtask 執(zhí)行。

setTimeout(() => {
 console.log("timer1")
 Promise.resolve().then(function() {
   console.log("promise1")
 })
}, 0)
process.nextTick(() => {
 console.log("nextTick")
 process.nextTick(() => {
   console.log("nextTick")
   process.nextTick(() => {
     console.log("nextTick")
     process.nextTick(() => {
       console.log("nextTick")
     })
   })
 })
})
// nextTick=>nextTick=>nextTick=>nextTick=>timer1=>promise1
五、Node 與瀏覽器的 Event Loop 差異

瀏覽器環(huán)境下,microtask 的任務(wù)隊列是每個 macrotask 執(zhí)行完之后執(zhí)行。而在 Node.js 中,microtask 會在事件循環(huán)的各個階段之間執(zhí)行,也就是一個階段執(zhí)行完畢,就會去執(zhí)行 microtask 隊列的任務(wù)

接下我們通過一個例子來說明兩者區(qū)別:

setTimeout(()=>{
    console.log("timer1")
    Promise.resolve().then(function() {
        console.log("promise1")
    })
}, 0)
setTimeout(()=>{
    console.log("timer2")
    Promise.resolve().then(function() {
        console.log("promise2")
    })
}, 0)

瀏覽器端運(yùn)行結(jié)果:timer1=>promise1=>timer2=>promise2

瀏覽器端的處理過程如下:

Node 端運(yùn)行結(jié)果:timer1=>timer2=>promise1=>promise2

全局腳本(main())執(zhí)行,將 2 個 timer 依次放入 timer 隊列,main()執(zhí)行完畢,調(diào)用棧空閑,任務(wù)隊列開始執(zhí)行;

首先進(jìn)入 timers 階段,執(zhí)行 timer1 的回調(diào)函數(shù),打印 timer1,并將 promise1.then 回調(diào)放入 microtask 隊列,同樣的步驟執(zhí)行 timer2,打印 timer2;

至此,timer 階段執(zhí)行結(jié)束,event loop 進(jìn)入下一個階段之前,執(zhí)行 microtask 隊列的所有任務(wù),依次打印 promise1、promise2

Node 端的處理過程如下:

六、總結(jié)

瀏覽器和 Node 環(huán)境下,microtask 任務(wù)隊列的執(zhí)行時機(jī)不同

Node 端,microtask 在事件循環(huán)的各個階段之間執(zhí)行

瀏覽器端,microtask 在事件循環(huán)的 macrotask 執(zhí)行完之后執(zhí)行

參考文章

瀏覽器進(jìn)程?線程?傻傻分不清楚!

事件循環(huán)機(jī)制的那些事

前端性能優(yōu)化原理與實(shí)踐

前端面試之道

深入理解 js 事件循環(huán)機(jī)制(Node.js 篇)

詳解 JavaScript 中的 Event Loop(事件循環(huán))機(jī)制

event-loop-timers-and-nexttick

關(guān)于Fundebug

Fundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應(yīng)用實(shí)時BUG監(jiān)控。 自從2016年雙十一正式上線,F(xiàn)undebug累計處理了9億+錯誤事件,付費(fèi)客戶有Google、360、金山軟件、百姓網(wǎng)等眾多品牌企業(yè)。歡迎大家免費(fèi)試用!

版權(quán)聲明

轉(zhuǎn)載時請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2019/01/15/diffrences-of-browser-and-node-in-event-loop/

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

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/101026.html

相關(guān)文章

  • 簡潔明了探索覽器Event loop

    摘要:前段時間我對于瀏覽器中的和哪個先執(zhí)行有所困惑,苦于搜索也沒有發(fā)現(xiàn)很明確的答案,于是決定深入探索瀏覽器,現(xiàn)有所愚見,想與大家分享,希望能幫助到那些還在爬坑的人。瀏覽器端中的異步隊列有兩種隊列和隊列。瀏覽器會不斷從隊列中按順序取執(zhí)行。 前段時間我對于瀏覽器Event loop中的MacroTask和MicroTask哪個先執(zhí)行有所困惑,苦于搜索也沒有發(fā)現(xiàn)很明確的答案,于是決定深入探索瀏覽器...

    DrizzleX 評論0 收藏0
  • FE.ES-理解Event Loop

    摘要:新加了一個微任務(wù)和一個宏任務(wù)在當(dāng)前執(zhí)行棧的尾部下一次之前觸發(fā)回調(diào)函數(shù)。階段這個階段主要執(zhí)行一些系統(tǒng)操作帶來的回調(diào)函數(shù),如錯誤,如果嘗試鏈接時出現(xiàn)錯誤,一些會把這個錯誤報告給。 JavaScript引擎又稱為JavaScript解釋器,是JavaScript解釋為機(jī)器碼的工具,分別運(yùn)行在瀏覽器和Node中。而根據(jù)上下文的不同,Event loop也有不同的實(shí)現(xiàn):其中Node使用了libu...

    longshengwang 評論0 收藏0
  • 最后一次搞懂 Event Loop

    摘要:由于是單線程的,這些方法就會按順序被排列在一個單獨(dú)的地方,這個地方就是所謂執(zhí)行棧。事件隊列每次僅執(zhí)行一個任務(wù),在該任務(wù)執(zhí)行完畢之后,再執(zhí)行下一個任務(wù)。 Event Loop 是 JavaScript 異步編程的核心思想,也是前端進(jìn)階必須跨越的一關(guān)。同時,它又是面試的必考點(diǎn),特別是在 Promise 出現(xiàn)之后,各種各樣的面試題層出不窮,花樣百出。這篇文章從現(xiàn)實(shí)生活中的例子入手,讓你徹底理解 E...

    gself 評論0 收藏0
  • [面試專題]JS異步原理(事件,隊列)

    摘要:全部代碼是一個先執(zhí)行一個執(zhí)行過程中遇到等異步操作則創(chuàng)建一個遇到等創(chuàng)建一個這兩個分別被掛起執(zhí)行棧為空時開始處理完成后處理直到該全部執(zhí)行完然后繼續(xù)主線程調(diào)用棧注每一次事件循環(huán),只處理一個。 JS異步原理(事件,隊列) 調(diào)用棧 JS執(zhí)行時會形成調(diào)用棧,調(diào)用一個函數(shù)時,返回地址、參數(shù)、本地變量都會被推入棧中,如果當(dāng)前正在運(yùn)行的函數(shù)中調(diào)用另外一個函數(shù),則該函數(shù)相關(guān)內(nèi)容也會被推入棧頂.該函數(shù)執(zhí)...

    LeoHsiun 評論0 收藏0
  • [面試專題]JS異步原理(事件,隊列)

    摘要:全部代碼是一個先執(zhí)行一個執(zhí)行過程中遇到等異步操作則創(chuàng)建一個遇到等創(chuàng)建一個這兩個分別被掛起執(zhí)行棧為空時開始處理完成后處理直到該全部執(zhí)行完然后繼續(xù)主線程調(diào)用棧注每一次事件循環(huán),只處理一個。 JS異步原理(事件,隊列) 調(diào)用棧 JS執(zhí)行時會形成調(diào)用棧,調(diào)用一個函數(shù)時,返回地址、參數(shù)、本地變量都會被推入棧中,如果當(dāng)前正在運(yùn)行的函數(shù)中調(diào)用另外一個函數(shù),則該函數(shù)相關(guān)內(nèi)容也會被推入棧頂.該函數(shù)執(zhí)...

    MageekChiu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<