async函式使用場景

Mango在掘金發表於2019-04-21

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的和。這就是所謂的同步方式執行非同步函式。 不過使用同步方式執行非同步函式的方式也有侷限性。

  1. 如果有耗時任務將會阻塞。 假如getA需要大約耗時10s,則getB不得不等到getA執行完畢。
  2. 如果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可以很爽地寫程式碼啦!

相關文章