摘要:任務(wù)隊列中的任務(wù)事件,一般有個共性就是存在回調(diào)函數(shù)。存放異步執(zhí)行的代碼,如定時器事件監(jiān)聽回調(diào)函數(shù)等,進(jìn)入等待狀態(tài)。總結(jié)的事件輪詢的機制,使任務(wù)隊列主線程異步操作之間可以相互協(xié)作。
從一道面試題說起
setTimeout(function() { console.log(111); }, 0); // 這里定時器時間設(shè)置為0ms后執(zhí)行 console.log(222);
相信這道題很多人都看過,結(jié)果是先輸出222,再輸出111
可能新手會犯錯,認(rèn)為定時器設(shè)置0毫秒就等于立即就執(zhí)行,所以先輸出111。但其實內(nèi)部涉及一個很重要的JS運行機制,也就是我們今天的主角——事件輪詢(Event Loop)
在聊Event Loop之前,有必要先講講JS的一些重要特點
JS的單線程JS的一大特點就是單線程,也就是說,同一個時間只能做一件事。那么,為什么JS不能有多個線程呢?
第一,為了提高效率,減少CPU的開銷。在多線程中,CPU需要來回切換線程,就會存在線程切換上的開銷。
第二,JS最初設(shè)計時,是作為瀏覽器的腳本語言,主要用途是與用戶互動,以及操作DOM。這就決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JS同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容,另一個線程刪除了這個節(jié)點,這時瀏覽器應(yīng)該以哪個線程為準(zhǔn)?
JS的異步說到JS的異步,可能有同學(xué)會問啦,JS是單線程的怎么還能異步執(zhí)行,這不是自相矛盾嗎?的確,單線程和異步確實不能同時成為一個語言的特性,所以它本身不可能是異步的。一定是存在一種機制讓它能夠異步執(zhí)行,往下看!
任務(wù)隊列JS是單線程就意味著,所有任務(wù)需要排隊,等前一個任務(wù)結(jié)束,才能執(zhí)行后一個任務(wù)。但前端的某些任務(wù)是非常耗時的,例如IO設(shè)備(輸入輸出設(shè)備)、Ajax操作(從網(wǎng)絡(luò)讀取數(shù)據(jù))、定時器...不得不等著結(jié)果出來,再往下執(zhí)行。如果讓他們和別的任務(wù)一樣,都老老實實的排隊等待執(zhí)行的話,執(zhí)行效率會非常的低,甚至導(dǎo)致頁面的假死,用戶體驗很差。
這個時候,任務(wù)隊列就派上用場了。
在JS中,所有任務(wù)可以分成兩種。一種是同步任務(wù),另一種是異步任務(wù)。
同步任務(wù)指的是,在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);異步任務(wù)指的是,不進(jìn)入主線程,而進(jìn)入"任務(wù)隊列"的任務(wù),只有"任務(wù)隊列"通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進(jìn)入主線程執(zhí)行。
任務(wù)隊列中的任務(wù)事件,一般有個共性就是存在"回調(diào)函數(shù)"。所謂"回調(diào)函數(shù)",就是那些會被主線程掛起來的代碼。異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)主線程開始執(zhí)行異步任務(wù)時,執(zhí)行就是對應(yīng)的回調(diào)函數(shù)。
值得一提的是,任務(wù)隊列不止一條。由于異步任務(wù)有很多種,比如事件監(jiān)聽類,定時器類,Ajax請求類...所以可以有很多條任務(wù)隊列
這樣說大家可能還不太明白,我畫個圖解釋下
Event Loop主線程從"任務(wù)隊列"中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為Event Loop(事件輪詢)。
執(zhí)行流程
(1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個執(zhí)行棧(每執(zhí)行一條代碼,向棧中壓入這條代碼)。 (2)主線程之外,還存在一個"任務(wù)隊列"。存放異步執(zhí)行的代碼,如定時器、事件監(jiān)聽回調(diào)函數(shù)等,進(jìn)入等待狀態(tài)。 (3)一旦主線程中的所有同步任務(wù)執(zhí)行完畢,就會讀取"任務(wù)隊列",看看里面有哪些任務(wù)。那些對應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。 (4)主線程不斷重復(fù)上面的第三步(輪詢)。
具體舉個例子吧
假如我們有一段代碼
var a = 11111 console.log(a) var btn1 = document.getElementById("btn1") btn1.onclick = function() { console.log(22222) } var btn2 = document.getElementById("btn2") btn2.onclick = function() { console.log(33333) } setTimeout(function() { console.log(44444) }, 1000) console.log(55555)
以上代碼在JS引擎中其實是這樣執(zhí)行的
var a = 11111 console.log(a) var btn1 = document.getElementById("btn1") var btn2 = document.getElementById("btn2") console.log(55555)
這五句代碼是同步代碼,會直接進(jìn)入主線程,依次執(zhí)行
btn.onclick = function() { console.log(22222) } btn2.onclick = function() { console.log(33333) } setTimeout(function() { console.log(44444) }, 1000)
這三塊異步代碼不會直接進(jìn)入主線程,而是先在相應(yīng)的任務(wù)隊列中注冊
當(dāng)主線程執(zhí)行完所有同步代碼時,就開始不斷輪詢?nèi)蝿?wù)隊列是否有任務(wù)需要執(zhí)行,輪詢的過程很快。在輪詢過程中,要是用戶點擊了btn1按鈕,任務(wù)隊列會通知主線程,"說我這有異步代碼已就緒,需要你來執(zhí)行"。這時btn1.onclick就從任務(wù)隊列中彈出,到主線程中執(zhí)行
同樣的,當(dāng)過了1s時,任務(wù)隊列會通知定時器需要執(zhí)行,這時主線程輪詢時得到這條"通知",所以就執(zhí)行定時器中語句
知道這個機制后,我們再回頭看看那個面試題
setTimeout(function() { console.log(111); }, 0); // 這里定時器時間設(shè)置為0ms后執(zhí)行 console.log(222);
這里的console.log(222) 首先在主線程中執(zhí)行,而定時器則是先在任務(wù)隊列中注冊。當(dāng)主線程中代碼執(zhí)行完(也就是console.log("222")這條語句執(zhí)行完后),主線程開始輪詢?nèi)蝿?wù)隊列中的異步代碼,由于定時器設(shè)置的時間是0ms,所以任務(wù)隊列會立即通知主線程,可以執(zhí)行。最后定時器就會到主線程中開始執(zhí)行。這就是為什么打印的結(jié)果先是222,后111。
總結(jié)JS的事件輪詢的機制,使任務(wù)隊列、JS主線程、異步操作之間可以相互協(xié)作。這正是JS語言與眾不同的運行方式,也因此使它具備了其他語言不具備的優(yōu)勢。
最后感謝大家百忙之中辛苦觀看,也希望這篇文章可以幫助屏幕前的你更好的理解JS的Event Loop機制!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/100757.html
摘要:整理收藏一些優(yōu)秀的文章及大佬博客留著慢慢學(xué)習(xí)原文協(xié)作規(guī)范中文技術(shù)文檔協(xié)作規(guī)范阮一峰編程風(fēng)格凹凸實驗室前端代碼規(guī)范風(fēng)格指南這一次,徹底弄懂執(zhí)行機制一次弄懂徹底解決此類面試問題瀏覽器與的事件循環(huán)有何區(qū)別筆試題事件循環(huán)機制異步編程理解的異步 better-learning 整理收藏一些優(yōu)秀的文章及大佬博客留著慢慢學(xué)習(xí) 原文:https://www.ahwgs.cn/youxiuwenzhan...
摘要:順便一說,這首歌的原唱是秋田,中島當(dāng)年嗓子壞了,才有這歌。中文是直接翻譯來的,作曲是秋田。一部電影春夏秋冬又一春春夏秋冬又一春是由金基德執(zhí)導(dǎo),金英民吳英秀金基德主演的一部韓國電影。年月日于韓國上映。 原鏈接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...
摘要:順便一說,這首歌的原唱是秋田,中島當(dāng)年嗓子壞了,才有這歌。中文是直接翻譯來的,作曲是秋田。一部電影春夏秋冬又一春春夏秋冬又一春是由金基德執(zhí)導(dǎo),金英民吳英秀金基德主演的一部韓國電影。年月日于韓國上映。 原鏈接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...
閱讀 2560·2023-04-26 01:44
閱讀 2567·2021-09-10 10:50
閱讀 1416·2019-08-30 15:56
閱讀 2270·2019-08-30 15:44
閱讀 517·2019-08-29 11:14
閱讀 3423·2019-08-26 11:56
閱讀 3022·2019-08-26 11:52
閱讀 911·2019-08-26 10:27