1. 程式人生 > 實用技巧 >promise、async和await之執行順序的那點事

promise、async和await之執行順序的那點事

首先在控制檯測試以下程式碼

async function async1(){
    console.log('2: async1 start')
    await async2()
    console.log('6: async1 end')
}
async function async2(){
    console.log('3: async2')
}
console.log('1: script start')
setTimeout(function(){
    console.log('8: setTimeout') 
},0)  
async1();
new Promise(function(resolve){
    console.log('4: promise1')
    resolve();
}).then(function(){
    console.log('7: promise2')
})
console.log('5: script end')

果然,實踐才是檢驗真理的唯一標準。執行的結果與原文說的不一樣。

小結一下理解的概念:

1、如果在函式定義時,在function前面加上async ,那麼在呼叫它以後,會返回一個Promise 物件(還是阮一峰老師說的精闢),如上面的async1()。

當執行async1時,一旦遇到其中的 await 就會先返回,等到觸發的非同步操作async2完成,再接著執行async1函式體內後面的語句。

2、Promise是一個立即執行函式。如上面編號為2、3、4的都是立即輸出,排在編號5之前。

上述程式碼我在console中執行多次順序不變。將setTimeout的延時時間由0改為3000也一樣。

如何讓編號7的語句在最後執行呢?辦法是將程式碼中的resolve()也用setTimeout()包起來,並設定延時為3000來檢視效果。

什麼是Async/Await?

async搭配await是ES7提出的,它的實現是基於Promise。

注意:await函式不能單獨使用,而且async函式返回的是一個Promise物件,可以使用then函式添加回調函式。當函式執行的時候,一旦遇到await函式就會先返回一個Promise物件,等到非同步操作完成,再去執行後面的語句。如果 await 後面的非同步操作出錯,那麼等同於 async 函式返回的 Promise 物件被 reject!
  • async/await是寫非同步程式碼的新方式,以前的方法有回撥函式和Promise。
  • async/await是基於Promise實現的,它不能用於普通的回撥函式。
  • async/await與Promise一樣,是非阻塞的。
  • async/await使得非同步程式碼看起來像同步程式碼,這正是它的魔力所在。

當然,如果不理解Promise的概念,可能對上面的內容還是不明白。

所以,下面簡單說一下Promise的概念

Promise是非同步程式設計的一種解決方案,我理解是為了解決js中的回撥地獄問題,讓程式碼更清晰。

ES6規定,Promise物件是一個建構函式,用來生成Promise例項

var promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 非同步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise例項具有then方法,也就是說,then方法是定義在原型物件Promise.prototype上的。

它的作用是為Promise例項新增狀態改變時的回撥函式。then方法的第一個引數是Resolved狀態的回撥函式,第二個引數(可選)是Rejected狀態的回撥函式。

new出來的Promise會保持一個pending狀態,當非同步操作完成(通常如訪問網址獲取資料),相應地呼叫resolve或reject;Promise的狀態由pending相應變更為fulfilled [實現] 或rejected[被否決] ,並且

1 當promise 狀態發生改變,就會觸發.then()裡的相應函式處理後續步驟

2 promise 狀態一經改變,不會再變

then方法返回的是一個新的Promise例項(注意,不是原來那個Promise例項)。因此可以採用鏈式寫法,即then方法後面再呼叫另一個then方法。

注意,Promise.reject()方法的引數,會原封不動地作為reject的理由,變成後續方法的引數。這一點與Promise.resolve方法不一致。

要區分幾個概念,第一,reject是用來丟擲異常的,catch是用來處理異常的;第二:reject是Promise的方法,而then和catch是Promise例項的方法(Promise.prototype.then 和 Promise.prototype.catch)。

catch只是一個語法糖而己 還是通過then來處理的

then的第二個引數和catch捕獲錯誤資訊的時候會就近原則,如果是promise內部報錯,reject丟擲錯誤後,then的第二個引數和catch方法都存在的情況下,只有then的第二個引數能捕獲到,如果then的第二個引數不存在,則catch方法會捕獲到。

建議總是使用catch方法,而不使用then方法的第二個引數。理由是第二種寫法可以捕獲前面then方法執行中的錯誤,也更接近同步的寫法(try/catch)。

算了,感覺還是一頭霧水。平時知道對new出來的promise物件連續呼叫then方法就好了,就像本文開頭的程式碼或下面的程式碼

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000);

}).then(function(result) {

  alert(result); // 1

  return new Promise((resolve, reject) => { // (*)
    setTimeout(() => resolve(result * 2), 1000);
  });

}).then(function(result) { // (**)

  alert(result); // 2

  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(result * 2), 1000);
  });

}).then(function(result) {

  alert(result); // 4

});

參考:https://segmentfault.com/a/1190000015057278

https://www.jianshu.com/p/79c9e6c961cd

https://blog.csdn.net/gogo_steven/article/details/103352762?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://blog.csdn.net/ligen52/article/details/82187682?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://blog.csdn.net/weixin_42470791/article/details/82560734

https://www.cnblogs.com/pu369/p/12523361.html