async/await 和 promise 的用法
參考:https://www.jianshu.com/p/ffa5cbe9ab29
async/await ”vs“ promise
寫法:
Promise
主要用then函數的鍊式調用,一直點點點,是一種從左向右的橫向寫法。
async/await
從上到下,順序執行,就像寫同步代碼一樣。這更符合人編寫代碼的習慣
參數數量
Promise
的then函數隻能傳遞一個參數,雖然可以通過包裝成對象,但是這會導緻傳遞備援資訊,頻繁的解析又重新組合參數,比較麻煩。
async/await
沒有這個限制,就當做普通的局部變量來處理好了,用let或者const定義的塊級變量,想怎麼用就怎麼用,想定義幾個就定義幾個,完全沒有限制,也沒有備援的工作。
機制
Promise
是根據函數式程式設計的範式,對異步過程進行了一層封裝。
async/await
是基于協程的機制,是真正的“儲存上下文,控制權切換 ... ... 控制權恢複,取回上下文”這種機制,是對異步過程更精确的一種描述。
async/await
async/await
是基于
Promise
的,是進一步的一種優化。不過再寫代碼的時候,
Promise
本身的API出現得很少,很接近同步代碼的寫法。
async
隻是表明裡面可能有異步過程,裡面可以有
await
關鍵字,如果沒有
async
函數本身會馬上傳回,不會阻塞目前線程。它的函數的傳回值是一個
Promise
對象。
當
return new Promise();
則直接處理promise對象
當
return data;
則相當于
Promise.resolve(data);
還是一個
Promise
對象
兩者都需要用用
.then(data => { })
函數處理。
await
的是
resolve(data)
消息,并把資料
data
傳回。比如,下面代碼中,當
Promise
對象由
Pending
變為
Resolved
的時候,變量
a
就等于
data
;然後再順序執行下面的語句`console.log(a);
const a = await new Promise((resolve, reject) => {
// async process ...
return resolve(data);
});
console.log(a);
await
等待的雖然是
promise
對象,但不必寫
.then(..)
,直接可以得到傳回值。
通過
await
标記的方法,隻有該方法執行完成之後才能往後執行
async function asyncFunction() {
console.time('asyncFunction total executing:');
const sleep1 = await sleep(2000);
console.log('sleep1: ' + sleep1);
const [sleep2, sleep3, sleep4]= await Promise.all([sleep(2000), sleep(1000), sleep(1500)]);
console.log('sleep2: ' + sleep2);
console.log('sleep3: ' + sleep3);
console.log('sleep4: ' + sleep4);
const sleepRace = await Promise.race([sleep(3000), sleep(1000), sleep(1000)]);
console.log('sleep race: ' + sleepRace);
console.timeEnd('asyncFunction total executing:');
return 'asyncFunction done.' // 這個可以不傳回,這裡隻是做個标記,為了顯示流程
}
-
這是第一個sleep1: sleep for 2000 ms
之後的第一個異步過程,後面的代碼,不論是同步和異步,都在等他執行完畢。await
-
這是第二個sleep2 ~ sleep4
之後的await
異步過程。這是“比慢模式”,三個Promise.all()
都完成後,再運作下面的代碼s,耗時最長的是sleep
;2000ms
-
這是第三個sleep race: sleep for 1000 ms
之後的await
異步過程。這是“比快模式”,耗時最短Promise.race()
都完成後,就運作下面的代碼。耗時最短的是sleep
;1000ms
-
這是最後的統計總共運作時間代碼。三個await之後的異步過程之和asyncFunction total executing:: 5006.276123046875ms
異常捕獲
對于異常的捕獲,除了傳統的try/catch
async getData() {
try {
this.formInfos = await getFormInfos();
} catch (e) {
Toast(`資料擷取失敗,請稍後重試`)
}
}
也可以通過.catch去捕獲異常
let books = await bookModel.fetchAll()
.catch((error) => { console.log(error); });
結合之後使用
const responseJson = await Promise.race([
fetch(url, requestConfig),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
])
.then((resPromise) => {
let resultPromise = resPromise.json()
return resultPromise
}).then((result) => {
return result
}).catch((e)=>{
throw new Error("網絡出現問題~")
})
if (responseJson['success']) {
return responseJson['obj']
} else {
throw new Error(responseJson['msg'])
}
注意:
-
隻能放在await
函數内部使用,不能放在普通函數裡面,否則會報錯。async
- 後面放
對象,在Promise
狀态時,相應的協程會交出控制權,進入等待狀态。這個是本質。Pending
-
後面也可以跟同步代碼,不過系統會自動轉化成一個await
對象。 比如Promise
其實就相當于const a = await 'hello world';
const a = await Promise.resolve('hello world');
-
隻關心異步過程成功的消息await
,拿到相應的資料resolve(data)
。至于失敗消息data
,不關心(可以放在一個reject(error)
結構中統一處理)try...catch
Promise
promise代表非阻塞異步執行的抽象,所謂的非阻塞異步執行就是,promise執行的時候,其他程式可以繼續往下執行,不必像await一樣,需要等待。
console.log('Starting Execution');
const promise = rp('http://example.com/');
promise.then(result => console.log(result));
console.log("Can't know if promise has finished yet...");
正确的使用方式
// 錯誤示範
async getBooksAndAuthor(authorId) {
const books = await bookModel.fetchAll();
const author = await authorModel.fetch(authorId);
return {
author,
books: books.filter(book => book.authorId === authorId),
};
}
// 這裡await之後就會阻塞,執行完一個執行下一個
// 正确姿勢
async getBooksAndAuthor(authorId) {
const bookPromise = bookModel.fetchAll();
const authorPromise = authorModel.fetch(authorId);
const book = await bookPromise;
const author = await authorPromise;
return {
author,
books: books.filter(book => book.authorId === authorId),
};
}
// promise會異步執行,的帶結果之後執行await