async await
async await
是非同步程式設計的另一種解決方案async
函式是對Generator
函式的改進
async的基本用法
async函式
async
函式返回一個 Promise
例項,可以使用then
方法(為返回的Promise例項)新增回撥函式。當函式執行的時候,一旦遇到await
就會先返回,等到非同步操作完成,再接著執行函式體內後面的語句。
例 1:
上面程式碼是一個獲取股票報價的函式,函式前面的
async
關鍵字,表明該函式內部有非同步操作。呼叫該函式時,會立即返回一個Promise
例項。async
函式內部return
語句返回的值,會成為then
方法回撥函式的引數。
Promise物件的狀態變化
async
函式返回的 Promise
物件,必須等到內部所有await
命令後面的 Promise
物件執行完,才會發生狀態改變,除非遇到return語句或者丟擲錯誤。也就是說,只有async
函式內部的非同步操作執行完,才會執行then
方法指定的回撥函式。
await命令的基本用法
正常情況下,await
命令後面是一個Promise
例項,如果不是,會被轉成一個立即resolve
的Promise
例項。
async function f() {
return await 123;
}
f().then(v => console.log(v))
等價於
async function f() {
return await new Promise(function(resolve){
resolve(123)
})
}
f().then(v => console.log(v))
等價於
async function f() {
return await Promise.resolve('123')
}
f().then(v => console.log(v))
await語句的返回值是await命令後面Promise例項的結果(非同步處理的結果)
function getResult() {
return new Promise((resolve) => {
resolve('result: 1000') // resolve()方法的引數就是非同步處理的結果
});
}
async function asyncPrint() {
const result = await getResult() // 將非同步處理的結果賦值給result
return result
}
asyncPrint().then( (result) => { console.log(result) } ) //'result: 1000'
異常處理
如果await
後面的非同步操作出錯,那麼等同於async
函式返回的 Promise
物件被reject
。
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出錯了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出錯了
防止出錯的方法,也是將其放在try...catch程式碼塊之中。
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出錯了');
});
} catch(e) {
}
return await('hello world');
}
使用注意
如果
await
後面的非同步操作出錯,那麼等同於async
函式返回的Promise
物件被reject
,所以最好把await
命令放在try...catch
程式碼塊中。
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一種寫法
async function myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err);
});
}
多個
await
命令後面的非同步操作,如果不存在繼發關係,最好讓它們同時觸發。
let foo = await getFoo();
let bar = await getBar();
上面程式碼中,getFoo
和getBar
是兩個獨立的非同步操作(即互不依賴),被寫成繼發關係(只有執行完getFoo操作,才能去執行getBar操作)。這樣比較耗時,因為只有getFoo
完成以後,才會執行getBar
,完全可以讓它們同時觸發。
解釋:這裡的getFoo
和getBar
方法會返回兩個Promise
例項(假設是發起Ajax請求,請求foo和bar的內容),只有執行了方法,對應的操作才會執行,如果寫成上面的形式,就會導致執行完getFoo
的操作後(等待收到伺服器的響應後),才能執行getBar
的操作,這樣就成了同步,比較耗時,因此可以將上面的寫法修改,使得在等待getFoo
執行完的時間內(在等待伺服器響應的期間)去執行執行getBar
記住:當函式執行的時候,一旦遇到await就會先返回,等到非同步操作完成,再接著執行函式體內後面的語句。
// 寫法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
上面兩種寫法,getFoo
和getBar
都是同時觸發,這樣就會縮短程式的執行時間。