在 事件迴圈 期間的某個時刻,運行時會從最先進入隊列的消息開始處理隊列中的消息。被處理的消息會被移出隊列,並作為輸入參數來調用與之關聯的函數。正如前面所提到的,調用一個函數總是會為其創造一個新的棧幀。函數的處理會一直進行到執行棧再次為空為止;然後事件迴圈將會處理隊列中的下一個消息(如果還有的話)。 ...
在 事件迴圈 期間的某個時刻,運行時會從最先進入隊列的消息開始處理隊列中的消息。被處理的消息會被移出隊列,並作為輸入參數來調用與之關聯的函數。正如前面所提到的,調用一個函數總是會為其創造一個新的棧幀。函數的處理會一直進行到執行棧再次為空為止;然後事件迴圈將會處理隊列中的下一個消息(如果還有的話)。
"執行至完成"
每一個消息完整地執行後,其它消息才會被執行。這為程式的分析提供了一些優秀的特性,包括:當一個函數執行時,它不會被搶占,只有在它運行完畢之後才會去運行任何其他的代碼,才能修改這個函數操作的數據。這個模型的一個缺點在於當一個消息需要太長時間才能處理完畢時,Web 應用程式就無法處理與用戶的交互,例如點擊或滾動。為了緩解這個問題,瀏覽器一般會彈出一個“這個腳本運行時間過長”的對話框。一個良好的習慣是縮短單個消息處理時間,併在可能的情況下將一個消息裁剪成多個消息。
函數 setTimeout
接受兩個參數:待加入隊列的消息和一個時間值(可選,預設為 0)。這個時間值代表了消息被實際加入到隊列的最小延遲時間。如果隊列中沒有其它消息並且棧為空,在這段延遲時間過去之後,消息會被馬上處理。但是,如果有其它消息,setTimeout
消息必須等待其它消息處理完。因此第二個參數僅僅表示最少延遲時間,而非確切的等待時間。
零延遲
零延遲並不意味著回調會立即執行。以 0 為第二參數調用 setTimeout
並不表示在 0 毫秒後就立即調用回調函數。
其等待的時間取決於隊列里待處理的消息數量。在下麵的例子中,"這是一條消息"
將會在回調獲得處理之前輸出到控制台,這是因為延遲參數是運行時處理請求所需的最小等待時間,但並不保證是準確的等待時間。
setTimeout
需要等待當前隊列中所有的消息都處理完畢之後才能執行,即使已經超出了由第二參數所指定的時間。
JS執行順序
- JS是從上到下一行一行執行。
- 如果某一行執行報錯,則停止執行下麵的代碼。
- 先執行同步代碼,再執行非同步代碼
事件迴圈的執行過程
- 同步代碼,調用棧執行後直接出棧
- 非同步代碼,放到Web API中,等待時機,等合適的時候放入回調隊列(callbackQueue),等到調用棧空時eventLoop開始工作,輪詢
- 微任務執行時機比巨集任務要早
- 微任務在DOM渲染前觸發,巨集任務在DOM渲染後觸發