async是Generator函式的語法糖,比起Generator更加具有語義。定義一個Generator函式需要類似於如下方式:
function * test(){
yield 1;
yield 2;
return 3
}
var a = test() //不會執行
a.next();
a.next();
複製程式碼
定義async函式只需要:
async function test(){
var a = await 1
var b = await 2
return b
}
test().then((res)=>{ // res為test函式的返回值。可見async會返回一個Promise物件
})
複製程式碼
在實際使用中await後面實際上更多的是一個非同步函式,例如一個promise物件的操作結果
// 模擬介面A
function getA(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
let res = Math.random()
if(res>0.5){
resolve(res)
} else {
reject(res)
}
},2000)
})
}
// 模擬介面B
function getB(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
let res = Math.random()
if(res>0.5){
resolve(res)
} else {
reject(res)
}
},2000)
})
}
async function print(){
let a = await getA().catch((error)=>{
console.log(error)
})
let b = await getB()
return [a,b]
}
print().then((res)=>{
console.log('成功',res)
}).catch((err)=>{
console.log('錯誤',err)
})
複製程式碼
上述print函式a變數值需要等到getA執行完畢才能獲得。getB需要await getA()執行完畢才會執行。所以print的執行時間是getA和getB的和。這就是所謂的同步方式執行非同步函式。 不過使用同步方式執行非同步函式的方式也有侷限性。
- 如果有耗時任務將會阻塞。 假如getA需要大約耗時10s,則getB不得不等到getA執行完畢。
- 如果async內有一個函式發生錯誤,則函式不再執行,錯誤將直接被catch捕捉,例如getA狀態為reject.則test().catch((error)=>{})將捕捉錯誤,getB不會執行。如果需要getB繼續執行,需要新增try...catch:
async function print(){
try{
let a = await getA()
}catch(error){
}
let b = await getB()
return [a,b]
}
複製程式碼
async使得非同步操作流程更加有序化,在promise中
getA()
getB()
複製程式碼
雖然getA定義在前面,但卻不一定會先於getB返回值,這樣在實際開發中可能給我們造成麻煩,因為實際開發中資料是由依賴的和有先後之分的。所以為了有序化,單純使用promise我們不得不使用如下類似程式碼:
getA().then(()=>{
return getB()
}).then(()=>{
return getC()
})
...
複製程式碼
寫的越多,程式碼就不具有可讀性,也不利於除錯。使用上述的async+await可以很爽地寫程式碼啦!