異步神器Async-await介紹與填坑

? async/await 是ES7中被提實(shí)現(xiàn)異步操作的技術(shù),相對比較新,好在babel爸爸已對它支持,我們可以歡快的對它進(jìn)行使用。了解async/await前要求對Promise有一定的理解,或可閱讀 深入理解 Promise 一文。盜圖

# async - 定義異步函數(shù)

? async 譯:異步,是 Generator 函數(shù)的語法糖。該函數(shù)會返回一個(gè)promise對象,可以使用then方法添加回調(diào)函數(shù),如果在函數(shù)內(nèi)直接 return,Async會通過Promise.resolve()將其封裝成Promise()對象,也可以通過.then添加回調(diào)函數(shù)

async function pms() {
  return 'abc'
}
console.log(pms())  // [object Promise] { ... }

? 以上方法執(zhí)行返回了一個(gè)promise對象,其執(zhí)行等效于

async function pms() {
  return new Promise((resolve, reject) => {
    resolve('abc')
  })
}

? 在沒有配合await時(shí),我們可以調(diào)用promise的.then方法得到執(zhí)行結(jié)果。當(dāng)然也會有.catch方法

pms().then(res => {
  console.log(res)  // 'abc'
}).catch(e => {
  console.log('錯(cuò)誤')
})

?

# await - 暫停異步函數(shù)的執(zhí)行

? await,即:async wait,旨在等待異步執(zhí)行結(jié)束,使用于async函數(shù)內(nèi)部。異步未執(zhí)行結(jié)束,阻塞當(dāng)前代碼。嗯哼?阻塞?。。?/strong>

? 與線程阻塞不同的是,await 的阻塞發(fā)生在 async 函數(shù)內(nèi)部,可以理解為一個(gè)異步的阻塞。跟在await后的JS表達(dá)式,可以等待很多類型的事件,但初衷是用于等待Promise對象。如果await的對象是promise對象,則阻塞異步函數(shù)代碼執(zhí)行等待promise的resolve狀態(tài),如果是同步執(zhí)行的表達(dá)式則立即執(zhí)行。
?

# async/await的使用

function asyncFunc(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {  // 用setTimeout模擬異步
      resolve('async result')
    }, time)
  })
}

function normalFunc() {
  console.log('normal result')
}

async function awaitDemo() {
  await normalFunc()  // 執(zhí)行立即打印 normal result
  const res = await asyncFunc(1000)
  console.log(res) // 執(zhí)行1s后打印 ‘a(chǎn)sync result’
}

awaitDemo() // 執(zhí)行 

? 以上的例子比較常規(guī),再看看下面這個(gè)例子

async function func() {
  console.log('123')
}
async function run() {
  const res = await func()
  console.log(res)  // 123
}
run()

? 該例子中,func看似一個(gè)普通函數(shù),但經(jīng)async定義后,會返回一個(gè)promise對象,此時(shí)的await等待的就是該promise對象的resolve參數(shù),即123
? 對比上一個(gè)例子中的normalFunc,主要有兩個(gè)理解點(diǎn)
(1)增加了async的普通函數(shù)變成了一個(gè)異步函數(shù),await等待的對象為promise對象,返回resolve參數(shù)
(2)await可以等待任何東西,如果等待的是普通內(nèi)容,則直接返回該內(nèi)容
?

# 【填坑1】異常處理

? 細(xì)心的你應(yīng)該已經(jīng)發(fā)現(xiàn),await 返回的是promise的resolve參數(shù),但對于catch卻沒有實(shí)際的處理。那當(dāng)我們的請求發(fā)生異常時(shí),該怎么辦?答案是使用try-catch,在Promise中的.catch()分支會流入catch

function asyncFunc(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {  // 用setTimeout模擬異步
      reject('promise reject')
    }, time)
  })
}
// 為了處理Promise.reject 的情況我們應(yīng)該將代碼塊用 try catch 捕獲一下
async function awaitDemo() {
  try {
    const res = await asyncFunc(1000)
    console.log(res)
  } catch (err) {
    console.log(err.message || 'Uncatch Error')
  }
}

awaitDemo()  // 如果沒有使用try-catch,執(zhí)行會報(bào)錯(cuò)

?

# 【填坑2】并行請求

? 對于一個(gè)真實(shí)的業(yè)務(wù)需求,通常會有多個(gè)異步請求需要同時(shí)執(zhí)行,如獲取左側(cè)目錄樹,和登錄賬戶的用戶信息等。因await遇到異步會阻塞,當(dāng)一個(gè)async函數(shù)內(nèi)有多個(gè)異步函數(shù)需要調(diào)用時(shí),就會出現(xiàn)相互等待的現(xiàn)象。天哪,“異步” 變成了 “同步”了,這不是我們所希望的

function asyncFunc() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('request done')
    })
  })
}
async function bugDemo() {
  await asyncFunc()
  await asyncFunc()
  await asyncFunc()
  console.log('finish')
}

? 以上代碼正常執(zhí)行了,沒有報(bào)出異常,但仔細(xì)觀察控制臺 timeline 可以發(fā)現(xiàn),三個(gè)函數(shù)是同步順序執(zhí)行的,其罪魁禍?zhǔn)拙褪?code>await的等待機(jī)制。那怎么解決這個(gè)問題?

? 其實(shí)async-await 只是promise的語法糖,但其并不能代替Promise,從對異常的處理上就可以看出,還需要引入try-catch ,本問題是另一個(gè)體現(xiàn)。解決辦法需要使用promise的.all()

promise.all( iterable ),當(dāng)所有請求都為resolve時(shí),返回resolve狀態(tài)

async function correctDemo() {
  const f1 = asyncFunc()
  const f2 = asyncFunc()
  const f3 = asyncFunc()
  await Promise.all([f1, f2, f3]);
  console.log('finish')
}

?

# 【填坑3】await必須在async的上下文中

? await 并不只是使用在async 函數(shù)中即可,還必須在asyn函數(shù)的上下文中

// 雖在async函數(shù)里使用,但在forEach上下文中,異常
async function errorDemo() {
    [1, 2, 3, 4, 5].forEach(item => {
        await item;
    });
}
errorDemo() // SyntaxError: await is only valid in async function
// await 必須在async函數(shù)的上下文中
async function correctDemo() {
    let arr = [1, 2, 3, 4, 5];
    for (let i = 0; i < arr.length; i ++) {
        await arr[i];
    }
}

?

# refs

async函數(shù)介紹
異步神器Async

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容