簡體   English   中英

javascript promises,事件循環和作業隊列

[英]javascript promises, the event loop, and the job queue

請考慮以下代碼:

function foo() {
    console.log('foo');

    new Promise(
        function(resolve, reject) {
            setTimeout(function() {
                resolve('RESOLVING');
            }, 5000);
        }
    )
    .then(
        function(value) {
            console.log(value);
        }
    );
}
foo();

我試圖理解這里發生的事情:

  1. 在執行new Promise ,直接運行“執行器函數”,並且當調用setTimeout時,將安排向“事件隊列”添加新條目的操作(5秒后)
  2. 因為調用then添加到“作業隊列”的操作,在Promise解決后組織調用傳遞的函數(記錄到控制台)
  3. 當執行setTimeout回調時(在事件循環的某個刻度上), Promise被解析,並且基於第2點, then調用的函數參數被添加到“作業隊列”並隨后執行。

注意我說[一個“工作隊列”],因為有一些我不確定的事情; 哪個“工作隊列是嗎?”。 我理解它的方式,“作業隊列”鏈接到“事件隊列”上的條目。 那么這就是上面例子中的setTimeout條目嗎? 假設在添加setTimeout的回調之前(和之后)沒有向“事件隊列”添加其他事件,主代碼的條目(對foo的調用)是否(通常)已經消失(運行完成)那個時候因為then的“作業隊列”條目沒有其他條目而不是setTimeout的鏈接到?

  1. 在執行new Promise ,直接運行“執行器函數”,並且當調用setTimeout時,將安排向“事件隊列”添加新條目的操作(5秒后)

是。 更具體地說,調用setTimeout使用瀏覽器的計時器機制來調度計時器; 大約五秒鍾后,計時器機制將作業添加到主要作業隊列中,該作業將調用您的回調。

  1. 因為調用then添加到“作業隊列”的操作,在Promise解決后組織調用傳遞的函數(記錄到控制台)

對。 then (使用單個參數)將一個履行處理程序添加到promise(並創建它返回的另一個promise)。 當promise解析時,調用處理程序的作業將添加到作業隊列中(但它是一個不同的作業隊列)。

  1. 當執行setTimeout回調時(在事件循環的某個刻度上), Promise被解析,並且基於第2點, then調用的函數參數被添加到“作業隊列”並隨后執行。

是的,但它不是同一個工作隊列。 :-)

主要的作業隊列就是事件處理程序和計時器回調等等。 主事件循環從隊列中獲取作業,將其運行至完成,然后選擇下一個作業等,如果沒有要運行的作業則空閑。

作業運行完成后,將運行另一個循環,該循環負責運行在該主作業期間計划的任何待處理的承諾作業。

在JavaScript規范中,主作業隊列稱為ScriptJobs,promise回調作業隊列為PromiseJobs。 在ScriptJob結束時,所有已排隊的PromiseJobs都會在下一個ScriptJob之前執行。 (在HTML規范中,它們的名稱是“task”[或“macrotask”]和“microtask”。)

是的,這確實意味着如果作業A和作業B都排隊,然后作業A被選中並安排一個承諾回調,則作業B運行之前運行該承諾回調,即使作業B已排隊(在主隊列)首先。

注意我說[一個“工作隊列”],因為有一些我不確定的事情; 哪個“工作隊列呢?”

希望我已經涵蓋了上述內容。 基本上:

  • 初始腳本執行,事件處理程序,計時器和requestAnimationFrame回調排隊到ScriptJobs隊列(主要隊列); 他們是“macrotasks”(或簡稱“任務”)。
  • Promise回調排隊到PromiseJobs隊列,該隊列在任務結束時處理為空。 也就是說,承諾回調是“微任務”。

我理解它的方式,“作業隊列”鏈接到“事件隊列”上的條目。

對於同樣的事情,這些只是不同的名稱。 JavaScript規范使用術語“作業”和“作業隊列”。 HTML規范使用“任務”和“任務隊列”和“事件循環”。 事件循環是從ScriptJobs隊列中獲取作業的。

那么這就是上面例子中的setTimeout條目嗎?

當計時器觸發時,作業將在ScriptJobs隊列中進行調度。

假設在添加setTimeout的回調之前(和之后)沒有向“事件隊列”添加其他事件,主代碼的條目(對foo的調用)是否(通常)已經消失(運行完成)那個時候因為then的“作業隊列”條目沒有其他條目而不是setTimeout的鏈接到?

基本上是的。 讓我們把它搞定:

  • 瀏覽器加載腳本並向ScriptJobs添加作業以運行腳本的頂級代碼。
  • 事件循環選擇該作業並運行它:
    • 該代碼定義了foo並調用它。
    • foo ,您執行console.log ,然后創建一個promise。
    • promise執行程序調度計時器回調:它將一個計時器添加到瀏覽器的計時器列表中。 它還沒有排隊工作。
    • then在promise中添加一個履行處理程序。
    • 那份工作結束了。
  • 大約五秒鍾后,瀏覽器向ScriptJobs添加一個作業來調用您的計時器回調。
  • 事件循環選擇該作業並運行它:
    • 回調解析了promise,它向PromiseJobs隊列添加了promise履行處理程序調用。
    • 該作業結束,但PromiseJobs中的條目,所以JavaScript引擎按順序循環遍歷:
      • 它獲取履行處理程序回調作業並運行它; 履行處理程序執行console.log
    • 那項工作現在完全完成了。

更多探索:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM