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/weixin_42470791/article/details/82560734
https://www.cnblogs.com/pu369/p/12523361.html