摘要:等到主任務(wù)隊(duì)列執(zhí)行完成時(shí)此時(shí)已打印,執(zhí)行存在隊(duì)列中的函數(shù),任務(wù)隊(duì)列中引入了任務(wù)隊(duì)列來(lái)執(zhí)行的回調(diào)函數(shù)。在這個(gè)的回調(diào)函數(shù)中使用創(chuàng)建一個(gè)的任務(wù),同時(shí)在中調(diào)用函數(shù)創(chuàng)建一個(gè)任務(wù)。
本文討論的事件循環(huán)均是基于瀏覽器環(huán)境上的,類(lèi)似nodejs環(huán)境下的事件循環(huán)與此并不相同。
讀者首先要對(duì)js單線程事件循環(huán)機(jī)制以及Promise有基本理解;如果這兩個(gè)概念不是很清楚,建議先閱讀下面兩篇文章:
THE JAVASCRIPT EVENT LOOP?;?Promise 對(duì)象
本文是基于THE JAVASCRIPT EVENT LOOP?,并對(duì)其內(nèi)容的延伸,所以下面提到的概念都按這篇文章的來(lái)。首先我會(huì)總結(jié)一下?THE JAVASCRIPT EVENT LOOP?。OK,讓我們開(kāi)始吧。
1,消息隊(duì)列(message queue)? ? ? 我們知道js單線程的實(shí)現(xiàn)方式會(huì)把異步任務(wù)(setTimeout回調(diào)函數(shù),事件監(jiān)聽(tīng)回調(diào)函數(shù)等)放在一個(gè)消息隊(duì)列中;當(dāng)主任務(wù)隊(duì)列任務(wù)為空時(shí)會(huì)去message queue查詢(xún)是否有等待執(zhí)行的任務(wù),如果有則執(zhí)行。
?例1:
var task_in_message_queue = () => {console.log("task in message queue")} setTimeout(task_in_message_queue,0); console.log("main task"); //result: //main task //task in message queue
setTimeout函數(shù)將task_in_message_queue函數(shù)添加到message queue隊(duì)列中。等到主任務(wù)隊(duì)列執(zhí)行完成時(shí)(此時(shí)已打印main task),執(zhí)行存在message queue隊(duì)列中的task_in_message_queue函數(shù)
2,任務(wù)隊(duì)列(job queue)? ? ? ? ES6中引入了任務(wù)隊(duì)列來(lái)執(zhí)行Promise的回調(diào)函數(shù)。同message queue一樣,job queue中的任務(wù)也是在主任務(wù)隊(duì)列為空時(shí)才開(kāi)始執(zhí)行。
例2:
var promise = new Promise((resolve,reject) => { resolve("task in job queue"); }); var resolve_callback = (resolve_message) => {console.log(resolve_message)} promise.then(resolve_callback); console.log("main task"); //result: //main task //task in job queue /** 這里有一個(gè)有趣的現(xiàn)象 在chrome中打印出的結(jié)果是 main task task in job queue undefined //主任務(wù)的函數(shù)返回值 在firefox中的結(jié)果是 main task undefined //主任務(wù)的函數(shù)返回值 task in job queue 感覺(jué)v8的實(shí)現(xiàn)是把job queue整合到了主任務(wù)隊(duì)列尾部 **/
promise.then 將promise?fulfilled狀態(tài)下的回調(diào)函數(shù)resolve_callback添加到j(luò)ob queue中。等到主任務(wù)隊(duì)列執(zhí)行完成時(shí)(此時(shí)已打印main task),執(zhí)行存在job queue隊(duì)列中的resolve_callback函數(shù)
這里有一點(diǎn)需要注意的是promise構(gòu)造函數(shù)會(huì)在主任務(wù)中立即執(zhí)行,例子如下:
var promise = new Promise((resolve,reject) => { resolve("task in job queue"); console.log("the promise construction executed"); }); var resolve_callback = (resolve_message) => {console.log(resolve_message)} promise.then(resolve_callback); console.log("main task"); //result: //the promise construction executed //main task //task in job queue3,任務(wù)隊(duì)列(job queue)VS 消息隊(duì)列(message queue)
? ? ? ?通過(guò)上面的例子我們知道主任務(wù)隊(duì)列優(yōu)先級(jí)是最高的,那么job queue和message queue哪個(gè)優(yōu)先級(jí)更高呢?答案是job queue,js會(huì)將job queue中的任務(wù)完全執(zhí)行完之后再執(zhí)行message queue中的任務(wù)。例子如下:
var message_task = () => {console.log("message task");} setTimeout(message_task,0); var promise1 = new Promise((resolve,reject) => { resolve("promise 1 resolved"); }); var promise2 = new Promise((resolve,reject) => { resolve("promise 2 resolved"); }); var resolve_callback = (resolve_message) => {console.log(resolve_message)} promise1.then(resolve_callback); promise2.then(resolve_callback); console.log("main task"); //result: //main task //promise 1 resolved //promise 2 resolved //message task /** 這里chrome和firefox返回undefined的位置同上面的例子一樣,也是不同的。有興趣的話可以試試看一下。 **/4,每次執(zhí)行message queue中的任務(wù)前都會(huì)檢查job queue嗎?
? ? ? ? 現(xiàn)在我們知道job queue的優(yōu)先級(jí)高于message queue。那么每次執(zhí)行message queue中任務(wù)前會(huì)檢查job queue嗎?我的意思是如果當(dāng)前job queue為空,message queue中有多個(gè)任務(wù)(假設(shè)有m_task1和m_task2)。js開(kāi)始執(zhí)行message queue中的任務(wù),在執(zhí)行完m_task1時(shí)插入了一個(gè)j_task1在job queue中。那么接下來(lái)是先執(zhí)行m_task2呢還是j_task1呢?如果先執(zhí)行了m_task2的話,就說(shuō)明js一旦開(kāi)始執(zhí)行message queue中的任務(wù)就會(huì)將所有message queue中任務(wù)執(zhí)行完再檢查其它任務(wù)隊(duì)列。如果先執(zhí)行j_task1的話,那么說(shuō)明再執(zhí)行每個(gè)message queue中的任務(wù)前都會(huì)先檢查其它任務(wù)隊(duì)列,先執(zhí)行優(yōu)先級(jí)高的任務(wù)隊(duì)列中的任務(wù)。為此我們用如下代碼來(lái)檢驗(yàn):
var promise_task = new Promise((resolve,reject) => { resolve("j_task1"); }); var resolve_callback = (resolve_message) => {console.log(resolve_message)} var message_task1 = () => { promise_task.then(resolve_callback); console.log("m_task1"); } var message_task2 = () => {console.log("m_task2");} setTimeout(message_task1,0); setTimeout(message_task2,0); //result: //m_task1 //j_task1 //m_task2
事實(shí)證明js在每次執(zhí)行message queue中的任務(wù)前都會(huì)檢查其它任務(wù)隊(duì)列(至少會(huì)檢查job queue),根據(jù)隊(duì)列優(yōu)先級(jí)決定先執(zhí)行哪個(gè)隊(duì)列中的任務(wù)。
5,主任務(wù)隊(duì)列呢?? ? ? ? 上面我們了解了job queue和message queue中任務(wù)的執(zhí)行順序,簡(jiǎn)而言之:在每次一個(gè)任務(wù)結(jié)束時(shí),js都會(huì)根據(jù)任務(wù)隊(duì)列的優(yōu)先級(jí)判斷下一個(gè)執(zhí)行任務(wù)是哪個(gè)。如果job queue中有任務(wù)則執(zhí)行job queue中的第一個(gè)任務(wù),否則執(zhí)行message queue中的第一個(gè)任務(wù)。那么主任務(wù)隊(duì)列是不是也一樣呢?(邏輯上應(yīng)該是一樣的,否則job queue或者message queue中的任務(wù)可以遞歸創(chuàng)建新任務(wù),這樣就永遠(yuǎn)無(wú)法回到主任務(wù)隊(duì)列了)。
? ? ? ? 即每次選擇執(zhí)行任務(wù)前(或者每次任務(wù)結(jié)束后),js會(huì)根據(jù)主任務(wù)隊(duì)列,job queue,message queue的優(yōu)先級(jí)來(lái)挑選將要執(zhí)行下一個(gè)任務(wù)是哪個(gè)。
? ? ? ? 為此我們聲明一個(gè)promise和一個(gè)message_task函數(shù)。在這個(gè)promise的回調(diào)函數(shù)中使用setTimeout創(chuàng)建一個(gè)message_task的message queue任務(wù),同時(shí)在message_task中調(diào)用promise.then 函數(shù)創(chuàng)建一個(gè)job queue 任務(wù)。這樣兩個(gè)任務(wù)會(huì)循環(huán)創(chuàng)建并循環(huán)執(zhí)行。運(yùn)行后我們會(huì)在console中看到兩個(gè)任務(wù)循環(huán)打印,這是我們?cè)赾onsole中鍵入alert("stop")命令。如果頁(yè)面顯示了alert,console停止了打印就說(shuō)明主任務(wù)隊(duì)列的行為方式和job queue,message queue是一樣的。否則的話,在這種情況下我們將永遠(yuǎn)無(wú)法回到主任務(wù)隊(duì)列。驗(yàn)證代碼如下:
var promise_task = new Promise((resolve,reject) => { resolve("j_task"); }); var resolve_callback = (resolve_message) => { setTimeout(message_task,0); console.log(resolve_message); } var message_task = () => { promise_task.then(resolve_callback); console.log("m_task"); } promise_task.then(resolve_callback); //result: //console會(huì)循環(huán)打印 j_task 和 m_task //這是在console中鍵入alert("stop")命令,觀察是否彈出alert框,console中打印是否終止
希望大家自行求證一下,當(dāng)然驗(yàn)證完畢后記得刷新頁(yè)面,不然可能就崩了。另:最好在chrome下驗(yàn)證,firefox有些卡頓。
總結(jié)? ? ? ? js事件循環(huán)規(guī)律可大致總結(jié)為如下:
? ? ? ? 1,js中有三個(gè)任務(wù)隊(duì)列:主任務(wù)隊(duì)列,job queue,message queue;
? ? ? ? 2,它們的優(yōu)先級(jí)是:主任務(wù)隊(duì)列 > job queue > message queue;
? ? ? ? 3,每當(dāng)要執(zhí)行下一個(gè)任務(wù)前(或者一個(gè)任務(wù)完成后),js會(huì)根據(jù)優(yōu)先級(jí)詢(xún)問(wèn)各個(gè)任務(wù)隊(duì)列是否為空,一旦遇到非空任務(wù)隊(duì)列時(shí)則取其第一個(gè)任務(wù)執(zhí)行。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99027.html
摘要:創(chuàng)建全局上下文由表示,并將全局上下文推到棧頂。在了解異步執(zhí)行之前還需要知道一些概念,事件循環(huán)和回調(diào)隊(duì)列也稱(chēng)為任務(wù)隊(duì)列或消息隊(duì)列。會(huì)等待事件循環(huán)調(diào)度。事件循環(huán)事件循環(huán)的作用是查看調(diào)用棧并確定調(diào)用棧是否空閑。 簡(jiǎn)評(píng):如果你對(duì) JavaScript 異步的原理感興趣,這里有一篇不錯(cuò)的介紹。 JavaScript 同步代碼是如果工作的 在介紹 JavaScript 異步執(zhí)行之前先來(lái)了解一下, ...
摘要:常見(jiàn)應(yīng)用則是為了完成一些更新應(yīng)用程序狀態(tài)的較小的任務(wù),如處理的回調(diào)和的修改,以便讓這些任務(wù)在瀏覽器重新渲染之前執(zhí)行。常見(jiàn)應(yīng)用執(zhí)行順序的實(shí)現(xiàn)需要至少一個(gè)和至少一個(gè)。 簡(jiǎn)介 我們?cè)谏弦黄?《淺析 JS 中的EventLoop 事件循環(huán)》 中提到一個(gè) Event Queue,其實(shí)在事件循環(huán)中 queue 一共有兩種,還有一種叫 Job Queue 其中 Event Queue 在 HTML...
摘要:同時(shí),如果執(zhí)行的過(guò)程中發(fā)現(xiàn)其他函數(shù),繼續(xù)入棧然后執(zhí)行。上面我們討論的其實(shí)都是同步代碼,代碼在運(yùn)行的時(shí)候只用調(diào)用棧解釋就可以了。 序 Event Loop 這個(gè)概念相信大家或多或少都了解過(guò),但是有一次被一個(gè)小伙伴問(wèn)到它具體的原理的時(shí)候,感覺(jué)自己只知道個(gè)大概印象,于是計(jì)劃著寫(xiě)一篇文章,用輸出倒逼輸入,讓自己重新學(xué)習(xí)這個(gè)概念,同時(shí)也能幫助更多的人理解它~ 概念 JavaScript 是一門(mén) ...
摘要:一旦這一切完成,方法會(huì)運(yùn)行在類(lèi)屬性在命令構(gòu)造后設(shè)置容器解析實(shí)例,在中我們?cè)O(shè)置了將使用的緩存驅(qū)動(dòng),我們也根據(jù)命令來(lái)決定我們調(diào)用什么方法。作業(yè)只在以上起效在上也無(wú)效處理作業(yè)方法調(diào)用觸發(fā)事件觸發(fā)事件。 譯文GitHub https://github.com/yuansir/diving-laravel-zh 原文鏈接https://divinglaravel.com/queue-system...
摘要:包括了操作例如事件綁定,這類(lèi)操作。每個(gè)結(jié)束后,都會(huì)進(jìn)行也就是檢查是否有在等待執(zhí)行,根據(jù)先進(jìn)先出,依次執(zhí)行。簡(jiǎn)單來(lái)說(shuō),會(huì)檢查是否有需要處理的,如果為空時(shí),則會(huì)按照先進(jìn)先出的順序來(lái)處理中的。 眾所周知, javascript是一個(gè)單線程語(yǔ)言。單線程也就意味著只有一個(gè)stack(調(diào)用棧),一次只能做一件事。那么又是如何實(shí)現(xiàn)異步操作?先來(lái)了解幾個(gè)關(guān)鍵的術(shù)語(yǔ)。 Call Stack 調(diào)用棧 sh...
閱讀 752·2021-09-28 09:35
閱讀 2591·2019-08-29 11:25
閱讀 2154·2019-08-23 18:36
閱讀 1849·2019-08-23 16:31
閱讀 2065·2019-08-23 14:50
閱讀 3112·2019-08-23 13:55
閱讀 3286·2019-08-23 12:49
閱讀 2074·2019-08-23 11:46