async 函數
async() : Generator 函數的文法糖。(
async
函數就是将 Generator 函數的星号( *
)替換成 async
,将 yield
替換成 await
,僅此而已。)
async和await兩種文法結合可以讓異步代碼像同步代碼一樣
// -傳回值:promise對象
// -promise對象的結果,由async函數執行的傳回值決定
async function fn() {
// return 'hello world';
// return傳回的結果如果不是一個promise類型的對象(例如:字元串),那麼函數的傳回結果就是一個成功的promise對象
// return傳回的結果是一個promise對象,那麼對象的結果由該對象決定
return new Promise((resolve, reject) => {
resolve('成功的資料');
// reject('失敗的資料');
})
}
var result = fn();
console.log(result); // Promise {<pending>}
await
// -await必須寫在async函數中
// -await右側的表達式一般為promise對象
// -await傳回的是promise成功的值
// -await的promise失敗了,就會抛出異常,需要通過try...catch捕獲處理
async
函數對 Generator 函數的改進,展現在以下四點。
async
(1)内置執行器。
Generator 函數的執行必須靠執行器,是以才有了
co
子產品,而
async
函數自帶執行器。也就是說,
async
函數的執行,與普通函數一模一樣,隻要一行。
asyncReadFile();
(2)更好的語義。
async
和
await
,比起*号和
yield
,語義更清楚了。
async
表示函數裡有異步操作,
await
表示緊跟在後面的表達式需要等待結果。
(3)更廣的适用性。
co
子產品約定,
yield
指令後面隻能是 Thunk 函數或 Promise 對象,而
async
函數的
await
指令後面,可以是 Promise 對象和原始類型的值(數值、字元串和布爾值,但這時會自動轉成立即 resolved 的 Promise 對象)。
(4)傳回值是 Promise。
async
函數的傳回值是 Promise 對象,這比 Generator 函數的傳回值是 Iterator 對象友善多了。你可以用
then
方法指定下一步的操作。
進一步說,
async
函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而
await
指令就是内部
then
指令的文法糖。
基本用法
async
函數傳回一個 Promise 對象,可以使用
then
方法添加回調函數。當函數執行的時候,一旦遇到
await
就會先傳回,等到異步操作完成,再接着執行函數體内後面的語句。
下面是一個例子,指定多少毫秒後輸出一個值。
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
上面代碼指定 50 毫秒以後,輸出
hello world
。
由于
async
函數傳回的是 Promise 對象,可以作為
await
指令的參數。是以,上面的例子也可以寫成下面的形式。
async function timeout(ms) {
await new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
async 函數有多種使用形式。
// 函數聲明
async function foo() {}
// 函數表達式
const foo = async function () {}
// 對象的方法
let obj = {
async foo() {}
}
obj.foo().then();
// class類的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jake').then(…);
// 箭頭函數
const foo = async () => {};
注意:
1、async函數在聲明形式上和普通函數沒有差別,函數聲明式,函數表達式,對象方法,class方法和箭頭函數等都可以聲明async函數。
2.任何一個await語句後面的 Promise 對象變為reject狀态,那麼整個async函數都會中斷執行。
3.async函數傳回的 Promise 對象,必須等到内部所有await指令後面的 Promise 對象執行完,才會發生狀态改變,除非遇到return語句或者抛出錯誤。也就是說,隻有async函數内部的異步操作執行完,才會執行then方法指定的回調函數。
文法
async
函數的文法規則總體上比較簡單,難點是錯誤處理機制。
async
函數傳回一個 Promise 對象。
async
函數内部
return
語句傳回的值,會成為
then
方法回調函數的參數。
async function foo() {
return 'hello world';
}
foo().then(v => console.log(v)); // hello world
async
函數内部抛出錯誤,會導緻傳回的 Promise 對象變為
reject
狀态。抛出的錯誤對象會被
catch
方法回調函數接收到。
async function foo() {
throw new Error('出錯了');
}
foo().then(v => console.log('resolve', v), e => console.log('reject', e)); // reject Error: 出錯了