詳解JS執(zhí)行隊列(JavaScript執(zhí)行順序),搞懂setTimeout方法到底是如何執(zhí)行的

定義:setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計算表達式。

舉個栗子:

image1.png

但是setTimeout真的有那么簡單嗎?到底setTimeout是不是異步執(zhí)行的呢?

沒這么簡單,再看一個栗子:

image2.png

我們在setTimeout里面指定了0ms,是希望這段代碼能立即執(zhí)行,但是實際上并沒有效果,而是先打印出了2,然后才是1,最后大約1s的時間打印3。
這是不是就說明setTimeout就是異步的呢?
如果是異步的同時執(zhí)行多個setTimeout()應(yīng)該同時會執(zhí)行,請再看下面的栗子:

image3.png

從上面的代碼可以知道,JS不是多線程的,那js就是單線程的?有么有異步執(zhí)行呢?

出現(xiàn)上面所有誤區(qū)的最主要一個原因是:我們潛意識中認為,JavaScript引擎有多個線程在執(zhí)行,JavaScript的定時器回調(diào)函數(shù)是異步執(zhí)行的.
而事實上的,JavaScript使用了障眼法,在多數(shù)時候騙過了我們的眼睛,這里得澄清一個事實:

JavaScript引擎是單線程運行的,瀏覽器無論在什么時候都只且只有一個線程在運行JavaScript程序。

除了主JavaScript執(zhí)行進程外,還需要一個在進程下一次空閑時執(zhí)行的代碼隊列(這個隊列就是監(jiān)聽執(zhí)行回調(diào)的)。
隨著頁面生命周期推移,代碼會按照執(zhí)行順序添加入隊列,例如當(dāng)按鈕被按下的時候他的事件處理程序會被添加到隊列中,并在下一個可能時間內(nèi)執(zhí)行。JavaScript中沒有任何代碼是立即執(zhí)行的,但一旦進程空閑則盡快執(zhí)行。
所以,定時器工作方式是當(dāng)特定時間過去后將代碼插入,但這并不意味著它會馬上執(zhí)行,只能表示它盡快執(zhí)行。
設(shè)定一個150ms后執(zhí)行的定時器,不代表150ms后它會馬上執(zhí)行,它只表示在150ms后被加入到執(zhí)行隊列中,如果這個時間點執(zhí)行隊列是空閑的,那么這段代碼就會被執(zhí)行;其他情況下,代碼可能明顯地等待更長時間才會去執(zhí)行。
看下面這個栗子:

image4.png

上面的例子里,一般的理解應(yīng)該是先打印0ms的再打印500ms的,但是,其實js在解析的時候遇到了setTimeout方法,第一次過了0ms后把延時0ms的優(yōu)先加入執(zhí)行隊列里,再在500ms后把延時500ms的其放入待執(zhí)行的隊列里,跳過去順序執(zhí)行下面的代碼,當(dāng)主線程中的代碼執(zhí)行完成后,js引擎去檢索待執(zhí)行的隊列有沒有待執(zhí)行的代碼,這時候就會發(fā)現(xiàn)setTimeout方法并順序執(zhí)行,(因為已經(jīng)過了定時器規(guī)定的延時時間,所以會立即執(zhí)行,兩個定時器的延時都是一樣的)。

JS執(zhí)行隊列總結(jié)

(1)所有同步任務(wù)都在主線程上執(zhí)行。
(2)主線程之外,還存在一個"任務(wù)隊列"(task queue)。只要異步任務(wù)有了運行結(jié)果,就在"任務(wù)隊列"之中放置一個事件。
(3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會讀取"任務(wù)隊列",看看里面有哪些事件。那些對應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進入主線程執(zhí)行棧,開始執(zhí)行。
(4)主線程不斷重復(fù)上面的第三步。

setTimeout方法、事件和回調(diào)函數(shù)(異步函數(shù))

"任務(wù)隊列"是一個先進先出的數(shù)據(jù)結(jié)構(gòu),排在前面的事件,優(yōu)先被主線程讀取。主線程的讀取過程基本上是自動的,只要執(zhí)行棧一清空,"任務(wù)隊列"上第一位的事件就自動進入主線程。但是,由于"定時器"功能和事件驅(qū)動等,主線程首先要檢查一下執(zhí)行時間或事件是否被觸發(fā),才能返回主線程。

當(dāng)一個JS文件中有很多回調(diào)函數(shù)的時候,我們無法確認哪個回調(diào)會先進入任務(wù)隊列。所以,遇到回調(diào)的時候要小心處理啦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容