async/await 非同步
async/await 是一個用同步的思維來解決非同步問題的方案。
async 函式就是 Generator 函式的語法糖。
async 函式的優點
async寫在function前面,該函式返回值是一個promise,可以直接使用then方法。
async function test() {
return "test";
}
test().then(function(v) {
console.log(v);
}); //“test”
await只能在async函式中使用。
async function test() { return "test"; } var v = await test(); console.log(v); //“test”
await不能工作在頂級作用域,需要將await程式碼包裹在一個async函式中
await接受thenables
就像promise.then,await也允許使用thenable物件(那些具有可呼叫的then方法的物件)。同樣,第三方物件可能不是一個promise,但是promise的相容性表示,如果它支援.then方法,那麼它就能用於await。
例如,這裡await接受了new Thenable(1)
class Test { constructor(str) { this.str= str; } then(resolve, reject) { setTimeout(() => { resolve(this.str); }, 1000); } } async function fun() { let result = await new Test("abc"); console.log(result); } fun();
如果await得到了一個帶有then方法的非promise物件,它將會呼叫提供原生函式resolve、reject作為引數的方法,然後await一直等待,直到他們其中的一個被呼叫。
async方法
一個class方法同樣能夠使用async,只需要將async放在它之前就可以
就像這樣:
class Waiter {
async wait () {
return await Promise.resolve(1)
}
}
new Waiter().wait().then(alert) // 1
這裡的意思是一樣的:它確保了返回值是一個promise,支援await
async、await序列並行處理
序列:等待前面一個await執行後接著執行下一個await,以此類推
async function test(str) {
return await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(str);
}, 1000);
})
}
var fun = async () => { //序列執行
console.time('fun');
console.log(await test('async 1'));
console.log(await test('async 2'));
console.log(await test('async 3'));
console.timeEnd('fun');
}
fun();
可以看到兩個await序列執行的總耗時為兩千多毫秒。
並行:將多個promise直接發起請求(先執行async所在函式),然後再進行await操作。
async function test(str) {
return await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(str);
}, 1000);
})
}
var fun1 = async () => { //並行執行
console.time('fun');
const t1 = test('async 1');
const t2 = test('async 2');
const t3 = test('async 3');
//直接列印
console.log(await t1);
console.log(await t2);
console.log(await t3);
console.timeEnd('fun');
}
var fun2 = async () => { //序列執行
console.time('fun2');
const t1 = test('async 1');
const t2 = test('async 2');
const t3 = test('async 3');
const t = [t1, t2, t3];
console.log(await Promise.all(t));
console.timeEnd('fun2');
}
fun1();
fun2();
fun1與fun2寫法效果基本無異
通過列印我們可以看到相對於序列執行,效率提升了一倍。在並行請求中先執行async的非同步操作再await它的結果,把多個序列請求改為並行可以將程式碼執行得更快,效率更高。
錯誤處理
可以使用try-catch語句捕獲錯誤,就像在正常丟擲中處理異常一樣。
如果我們不使用try-catch,然後async函式的呼叫產生的promise變成reject狀態的話,我們可以新增.catch去處理它:
如果我們忘記新增.catch,我們就會得到一個未被處理的promise錯誤(能夠在控制檯裡看到它),這時我們可以通過使用一個全域性的事件處理器去捕獲錯誤。
async function myFun() {
try {
await fun();
} catch (err) {
console.log(err);
}
}
// 另一種寫法
async function myFun() {
await fun().catch(function (err){
console.log(err);
});
}
總結
放在一個函式前的async有兩個作用:
1)使函式總是返回一個promise
2)允許在這其中使用await
有了async/await,很少需要寫promise.then/catch,但是Promise.all沒有替代方式,它能夠同時等待很多工。
async/await對比Promise優點:
1) 真正地用同步的方式寫非同步程式碼
2) 不用寫then及其回撥函式,減少程式碼行數,也避免了程式碼巢狀
3) 所有非同步呼叫可以寫在同一個程式碼塊中,無需定義多餘的中間變數
4) async函式會隱式地返回一個Promise,因此可以直接return變數,無需使用Promise.resolve進行轉換