關(guān)于promise的執(zhí)行順序問題

看到這樣一段代碼

Promise.resolve().then(() => {
  console.log(0);
  return Promise.resolve(4) // p2
}).then((res) => {
  console.log(res)
})

Promise.resolve().then(() => {
  console.log(1);
}).then(() => {
  console.log(2);
}).then(() => {
  console.log(3);
}).then(() => {
  console.log(5);
}).then(() =>{
  console.log(6);
})
result: 0123456

對此結(jié)果非常疑惑,百思不得其解,本來覺得結(jié)果應(yīng)該是0142356

最后經(jīng)過多方搜索,在知乎山看到這樣一個問題關(guān)于promise輸出順序的疑問?, 紫云飛大大的回答解決了我的疑惑,但是大大的解答太過抽象,我也是自己摸索好久才萬全明白,在此記錄一下。

問題的關(guān)鍵在于在promise內(nèi)部返回一個thenable對象會發(fā)生什么?
1、promise的then是一個microtask微任務(wù)
2、promise p return一個promise p2的時候,其實是將這個p2的then加入到了微任務(wù)隊列中,同時將p的resolve和reject傳給p2
3、p2中的then全部調(diào)用完成之后,會將p的resolve放入微任務(wù)隊列,resolve完成之后,這個時候p的狀態(tài)才會變化,繼續(xù)執(zhí)行p的then

所以以上代碼的執(zhí)行過程就是:

輸出 微任務(wù)隊列
[0, 1]
0 [1, p2-then]
1 [p2-then, 2]
[2, resolve]
2 [resolve, 3]
[3, 4]
3 [4, 5]
4 [5, 6]
5 [6]
6 []

一下是幾個例子,加深一下理解(隊列中的元素對應(yīng)的是元素所在的then)

Example1
new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    return new Promise((resolve, reject) => {
      console.log("內(nèi)部promise");
      resolve();
    })
    .then(() => {
    console.log("內(nèi)部第一個then");
    })
    .then(() => {
    console.log("內(nèi)部第二個then");
    });
  })
  .then(() => {
    console.log("外部第二個then");
  });
輸出 微任務(wù)隊列
外部promise [外部第一個then]
外部第一個then []
內(nèi)部promise [內(nèi)部第一個then]
內(nèi)部第一個then [內(nèi)部第二個then]
內(nèi)部第二個then [resolve]
[外部第二個then]
外部第二個then []
Example2
new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    new Promise((resolve, reject) => {
      console.log("內(nèi)部promise");
      resolve();
    })
      .then(() => {
        console.log("內(nèi)部第一個then");
      })
      .then(() => {
        console.log("內(nèi)部第二個then");
      });
  })
  .then(() => {
    console.log("外部第二個then");
  });
輸出 微任務(wù)隊列
外部promise [外部第一個then]
外部第一個then []
內(nèi)部promise [內(nèi)部第一個then]
[內(nèi)部第一個then, 外部第二個then]
內(nèi)部第一個then [外部第二個then, 內(nèi)部第二個then]
外部第二個then [內(nèi)部第二個then]
內(nèi)部第二個then []
Example3
new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    let p = new Promise((resolve, reject) => {
      console.log("內(nèi)部promise");
      resolve();
    })
    p.then(() => {
        console.log("內(nèi)部第一個then");
      })
    p.then(() => {
        console.log("內(nèi)部第二個then");
      });
  })
  .then(() => {
    console.log("外部第二個then");
  });
輸出 微任務(wù)隊列
外部promise [外部第一個then]
外部第一個then []
內(nèi)部promise [內(nèi)部第一個then]
[內(nèi)部第一個then,內(nèi)部第二個then]
[內(nèi)部第一個then, 內(nèi)部第二個then, 外部第二個then]
內(nèi)部第一個then [內(nèi)部第二個then, 外部第二個then]
內(nèi)部第二個then [外部第二個then]
外部第二個then []
Example4
let p = new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
p.then(() => {
    console.log("外部第一個then");
    new Promise((resolve, reject) => {
      console.log("內(nèi)部promise");
      resolve();
    })
      .then(() => {
        console.log("內(nèi)部第一個then");
      })
      .then(() => {
        console.log("內(nèi)部第二個then");
      });
  })
p.then(() => {
    console.log("外部第二個then");
  });
輸出 微任務(wù)隊列
外部promise [外部第一個then, 外部第二個then]
外部第一個then 內(nèi)部promise [外部第二個then, 內(nèi)部第一個then]
外部第二個then [內(nèi)部第一個then, 內(nèi)部第二個then]
內(nèi)部第一個then [內(nèi)部第二個then]
內(nèi)部第二個then []
Example5
new Promise((resolve, reject) => { // p
  console.log('外部promise');
  resolve();
})
  .then(() => {
    console.log('外部第一個then');
    new Promise((resolve, reject) => { // p2
      console.log('內(nèi)部promise');
      resolve();
    })
      .then(() => {
        console.log('內(nèi)部第一個then');
        return Promise.resolve(); // p3
      })
      .then(() => {
        console.log('內(nèi)部第二個then');
      })
  })
  .then(() => {
    console.log('外部第二個then');
  })
  .then(() => {
    console.log('外部第三個then');
  })
輸出 微任務(wù)隊列
外部promise [外部第一個then]
外部第一個then 內(nèi)部promise [內(nèi)部第一個then]
[內(nèi)部第一個then, 外部第二個then]
內(nèi)部第一個then [ 外部第二個then, p3-then]
外部第二個then [p3-then, 外部第三個then]
[外部第三個then, p2-resolve]
外部第三個then [p2-resolve]
[內(nèi)部第二個then]
內(nèi)部第二個then []
Example6
new Promise((resolve, reject) => { // p
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一個then");
    new Promise((resolve, reject) => { // p2
      console.log("內(nèi)部promise");
      resolve();
    })
      .then(() => {
        console.log("內(nèi)部第一個then");
      })
      .then(() => {
        console.log("內(nèi)部第二個then");
      });
    return new Promise((resolve, reject) => { // p3
      console.log("內(nèi)部promise2");
      resolve();
    })
      .then(() => {
        console.log("內(nèi)部第一個then2");
      })
      .then(() => {
        console.log("內(nèi)部第二個then2");
      });
  })
  .then(() => {
    console.log("外部第二個then");
  });
輸出 微任務(wù)隊列
外部promise [外部第一個then]
外部第一個then 內(nèi)部promise [內(nèi)部第一個then]
內(nèi)部promise2 [內(nèi)部第一個then, 內(nèi)部第一個then2]
內(nèi)部第一個then [內(nèi)部第一個then2, 內(nèi)部第二個then]
內(nèi)部第一個then2 [內(nèi)部第二個then, 內(nèi)部第二個then2]
內(nèi)部第二個then [內(nèi)部第二個then2]
內(nèi)部第二個then2 [p-resolve]
[外部第二個then]
外部第二個then []
Example7
new Promise((resolve, reject) => { // p
  console.log("外部promise");
  resolve();
})
.then(() => {
    console.log("外部第一個then");
    new Promise((resolve, reject) => { // p2
        console.log("內(nèi)部promise");
        resolve();
    })
    .then(() => {
        console.log("內(nèi)部第一個then");
    })
    .then(() => {
        console.log("內(nèi)部第二個then");
    });
    return new Promise((resolve, reject) => { // p3
        console.log("內(nèi)部promise2");
        resolve();
    })
    .then(() => {
        console.log("內(nèi)部第一個then2");
    })
    .then(() => {
        console.log("內(nèi)部第二個then2");
    });
})
.then(() => {
    console.log("外部第二個then");
});
輸出 微任務(wù)隊列
外部promise [外部第一個then]
外部第一個then 內(nèi)部promise [內(nèi)部第一個then]
內(nèi)部promise2 [內(nèi)部第一個then, 內(nèi)部第一個then2]
內(nèi)部第一個then [內(nèi)部第一個then2, 內(nèi)部第二個then]
內(nèi)部第一個then2 [內(nèi)部第二個then, 內(nèi)部第二個then2]
內(nèi)部第二個then [內(nèi)部第二個then2]
內(nèi)部第二個then2 [p-resolve]
[外部第二個then]
外部第二個then []

2021年8月31日
最近手動寫了一遍Promise,可能有點晚。但是明白了為什么promise返回一個promise的時候會需要等一下才能顯示,因為Promise的resolvePromise(x, promise, resolve, reject)方法,如果x是一個promise,那么會調(diào)用一次then.call(x, y => {resolvePromise(y, promise, resolve, reject)}, reject), then是微服務(wù),所以需要再次進入微服務(wù)隊列排隊,所以會有這樣的現(xiàn)象

最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

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