
文章插圖
異步簡(jiǎn)單地說 , JavaScript 是單線程執(zhí)行的語言 , 但在使用中有很多異步執(zhí)行的情況 。異步的本質(zhì)是用其他方式(相對(duì)同步)控制程序的執(zhí)行順序 , 這與其他語言中的多線程模型不同 , 所以常常有人對(duì)非順序 JavaScript 代碼的運(yùn)行結(jié)果感到困惑不解 。
一段簡(jiǎn)單的小程序任何使用過 JavaScript 的程序員都能說出下面這段代碼的輸出:
console.log("A");setTimeout(() => {console.log("B");}, 100);console.log("C");先后順序是 A、C、B , 因?yàn)榈诙€(gè)參數(shù)的作用是指定延遲的毫秒數(shù) , 這段代碼只有一個(gè) setTimeout , 所以不會(huì)讓人迷惑 。
對(duì)類似程序的解釋通常是由 setTimeout 設(shè)置一個(gè)定時(shí)器 , 在指定毫秒數(shù)后調(diào)用回調(diào)函數(shù) 。然而 , 它的執(zhí)行機(jī)制并不是這么簡(jiǎn)單 。實(shí)際上 , setTimeout 的作用是在指定的毫秒數(shù)之后 , 在得到機(jī)會(huì)時(shí) , 將 callback 放入 Event Loop Queue 。
Event Loop首先要拋出一些概念 , 通常所說的 JavaScript Engine 是指負(fù)責(zé)執(zhí)行一個(gè)一個(gè) chunk 的程序 , 它依賴宿主環(huán)境的調(diào)度 , 也需要通過宿主環(huán)境與操作系統(tǒng)產(chǎn)生關(guān)聯(lián)并得到支持 。JavaScript Engine 是 JavaScript Runtime(Hosting Environment) 的一部分 。
每個(gè) chunk 通常是以 function 為單位 , 一個(gè) chunk 執(zhí)行完成后 , 才會(huì)執(zhí)行下一個(gè) chunk 。下一個(gè) chunk 是什么呢?取決于當(dāng)前 Event Loop Queue 中的隊(duì)首 。Event Loop Queue 中存放的都是消息 , 每個(gè)消息關(guān)聯(lián)著一個(gè)函數(shù) , JavaScript Engine 就按照隊(duì)列中的消息順序執(zhí)行它們 , 也就是執(zhí)行 chunk 。
所以上面的 setTimeout 實(shí)際執(zhí)行起來更接近這樣:
chunk1執(zhí)行:由 setTimeout 啟動(dòng)定時(shí)器(100毫秒)chunk2執(zhí)行:得到機(jī)會(huì) , 將 callback 放入 Event Loop Queuechunk3執(zhí)行:此 callback 執(zhí)行不難發(fā)現(xiàn) , 得到機(jī)會(huì)很重要!這也就可以解釋用 setTimeout 延遲 1000 不一定是準(zhǔn)確的 , 而是會(huì)至少延遲一秒 。因?yàn)槿绻€有其他的任務(wù)在前面 , 它要等待那些任務(wù)對(duì)應(yīng)的消息都出隊(duì) , 也就是程序都執(zhí)行完成 , 它才能將 callback 放入隊(duì)列 。也就是實(shí)際延遲會(huì)大于或等于一秒 。
通常所說的觸發(fā)了一個(gè)事件 , 就是指這個(gè) event listener 得到了執(zhí)行 。與 setTimeout 這個(gè)例子中的概念一樣 , 這也是一次 chunk 的執(zhí)行 。像這樣一個(gè)一個(gè)執(zhí)行 chunk 的過程就叫 Event Loop 。
還有一個(gè)經(jīng)常提到的概念叫「無阻塞」 , JavaScript 中的無阻塞就是指這種 Event Loop 模型 。除去 alert 或同步 Ajax 請(qǐng)求等歷史原因造成的問題 , 程序總是不會(huì)出現(xiàn)阻塞;也就是說 JavaScript Engine 總是可以處理下一個(gè)任務(wù) , 如處理用戶對(duì)瀏覽器的操作 。
一些簡(jiǎn)單的小例子將 setTimeout 加入 try 語句之中 , 結(jié)果會(huì)如何?
try {setTimeout(() => {throw new Error("Error - from try statement");}, 0);} catch (e) {console.error(e);}try catch 與 setTimeout 不在同一個(gè) chunk , 所以……你懂的 。
再看下一個(gè) 。
下面的堆棧信息會(huì)輸出 C – B – A 嗎?
setTimeout(function A() {setTimeout(function B() {setTimeout(function C() {throw new Error("Error - from function C");}, 0);}, 0);}, 0);它們并不對(duì)應(yīng)同一條 Event Loop Queue 中的消息 , 分別有各自的調(diào)用棧 , 所以錯(cuò)誤棧里面只有 C 。
Job QueueJob 是 ES6 中新增的概念 , 它與 Promise 的執(zhí)行有關(guān) , 可以理解為等待執(zhí)行的任務(wù);Job Queue 就是這種類型的任務(wù)的隊(duì)列 。JavaScript Runtime 對(duì)于 Job Queue 與 Event Loop Queue 的處理有所不同 。
以上關(guān)于本文的內(nèi)容,僅作參考!溫馨提示:如遇健康、疾病相關(guān)的問題,請(qǐng)您及時(shí)就醫(yī)或請(qǐng)專業(yè)人士給予相關(guān)指導(dǎo)!
「愛刨根生活網(wǎng)」www.malaban59.cn小編還為您精選了以下內(nèi)容,希望對(duì)您有所幫助:- matlab中ode45函數(shù)的用法 matlab求解微分方程組例題
- javascript定義數(shù)組的方法 js創(chuàng)建數(shù)組的幾種方式
- 互聯(lián)網(wǎng)常識(shí):如何在IE瀏覽器中禁用JavaScript
- web前端開發(fā)語言 javascript基礎(chǔ)知識(shí)總結(jié)
- 高中數(shù)學(xué)函數(shù)講解 指數(shù)函數(shù)知識(shí)點(diǎn)總結(jié)
- java與javascript的區(qū)別 什么是超文本傳輸協(xié)議
- 網(wǎng)絡(luò)延遲是什么意思?影響網(wǎng)速,對(duì)吧?你能給我舉個(gè)例子嗎? 網(wǎng)絡(luò)延時(shí)是什么意思
- 三角形公式全集。 三角形公式
- Python列表常用操作小技巧 python中map函數(shù)的用法
- php遞歸算法經(jīng)典實(shí)例 php遞歸函數(shù)的遞歸層級(jí)
