淺談async/await

ES7的async/await語(yǔ)法在2016年就已經(jīng)提出來(lái)了,慚愧的是我最近才接觸使用,,下面來(lái)聊聊

解決了什么問(wèn)題

在async/await之前,我們有三種方式寫(xiě)異步代碼

  1. 嵌套回調(diào)

  2. 以Promise為主的鏈?zhǔn)交卣{(diào)

  3. 使用Generators

但是,這三種寫(xiě)起來(lái)都不夠優(yōu)雅,ES7做了優(yōu)化改進(jìn),async/await應(yīng)運(yùn)而生,async/await相比較Promise 對(duì)象then 函數(shù)的嵌套,與 Generator 執(zhí)行的繁瑣(需要借助co才能自動(dòng)執(zhí)行,否則得手動(dòng)調(diào)用next() ), Async/Await 可以讓你輕松寫(xiě)出同步風(fēng)格的代碼同時(shí)又擁有異步機(jī)制,更加簡(jiǎn)潔,邏輯更加清晰。

async/await特點(diǎn)

  1. async/await更加語(yǔ)義化,async 是“異步”的簡(jiǎn)寫(xiě),async function 用于申明一個(gè) function 是異步的; await,可以認(rèn)為是async wait的簡(jiǎn)寫(xiě), 用于等待一個(gè)異步方法執(zhí)行完成;

  2. async/await是一個(gè)用同步思維解決異步問(wèn)題的方案(等結(jié)果出來(lái)之后,代碼才會(huì)繼續(xù)往下執(zhí)行)

  3. 可以通過(guò)多層 async function 的同步寫(xiě)法代替?zhèn)鹘y(tǒng)的callback嵌套

async function語(yǔ)法

  • 自動(dòng)將常規(guī)函數(shù)轉(zhuǎn)換成Promise,返回值也是一個(gè)Promise對(duì)象

  • 只有async函數(shù)內(nèi)部的異步操作執(zhí)行完,才會(huì)執(zhí)行then方法指定的回調(diào)函數(shù)

  • 異步函數(shù)內(nèi)部可以使用await

async function name([param[, param[, ... param]]]) { statements }
name: 函數(shù)名稱(chēng)。
param:  要傳遞給函數(shù)的參數(shù)的名稱(chēng)
statements: 函數(shù)體語(yǔ)句。
返回值: 返回的Promise對(duì)象會(huì)以async function的返回值進(jìn)行解析,或者以該函數(shù)拋出的異常進(jìn)行回絕。
image.png

await語(yǔ)法

  • await 放置在Promise調(diào)用之前,await 強(qiáng)制后面點(diǎn)代碼等待,直到Promise對(duì)象resolve,得到resolve的值作為await表達(dá)式的運(yùn)算結(jié)果

  • await只能在async函數(shù)內(nèi)部使用,用在普通函數(shù)里就會(huì)報(bào)錯(cuò)

[return_value] = await expression;

expression:  一個(gè) Promise  對(duì)象或者任何要等待的值。

返回值:返回 Promise 對(duì)象的處理結(jié)果。如果等待的不是 Promise 對(duì)象,則返回該值本身。
image.png

錯(cuò)誤處理

在async函數(shù)里,無(wú)論是Promise reject的數(shù)據(jù)還是邏輯報(bào)錯(cuò),都會(huì)被默默吞掉,所以最好把a(bǔ)wait放入try{}catch{}中,catch能夠捕捉到Promise對(duì)象rejected的數(shù)據(jù)或者拋出的異常

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject('error')}, ms);  //reject模擬出錯(cuò),返回error

  });

}

async function asyncPrint(ms) {

  try {

     console.log('start');

     await timeout(ms);  //這里返回了錯(cuò)誤

     console.log('end');  //所以這句代碼不會(huì)被執(zhí)行了

  } catch(err) {

     console.log(err); //這里捕捉到錯(cuò)誤error

  }

}

asyncPrint(1000);

如果不用try/catch的話(huà),也可以像下面這樣處理錯(cuò)誤(因?yàn)閍sync函數(shù)執(zhí)行后返回一個(gè)promise)

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject('error')}, ms);  //reject模擬出錯(cuò),返回error

  });

}

async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms)

  console.log('end');  //這句代碼不會(huì)被執(zhí)行了

}

asyncPrint(1000).catch(err => {

    console.log(err); // 從這里捕捉到錯(cuò)誤

});

如果你不想讓錯(cuò)誤中斷后面代碼的執(zhí)行,可以提前截留住錯(cuò)誤,像下面

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {

        reject('error')

    }, ms);  //reject模擬出錯(cuò),返回error

  });

}

async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms).catch(err => {  // 注意要用catch

console.log(err) 

  })

  console.log('end');  //這句代碼會(huì)被執(zhí)行

}

asyncPrint(1000);

使用場(chǎng)景

多個(gè)await命令的異步操作,如果不存在依賴(lài)關(guān)系(后面的await不依賴(lài)前一個(gè)await返回的結(jié)果),用Promise.all()讓它們同時(shí)觸發(fā)

function test1 () {
    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(1)

        }, 1000)

    })

}

function test2 () {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(2)

        }, 2000)

    })

}

async function exc1 () {

    console.log('exc1 start:',Date.now())

    let res1 = await test1();

    let res2 = await test2(); // 不依賴(lài) res1 的值

    console.log('exc1 end:', Date.now())

}

async function exc2 () {

    console.log('exc2 start:',Date.now())

    let [res1, res2] = await Promise.all([test1(), test2()])

    console.log('exc2 end:', Date.now())

}

exc1();

exc2();

exc1 的兩個(gè)并列await的寫(xiě)法,比較耗時(shí),只有test1執(zhí)行完了才會(huì)執(zhí)行test2

你可以在瀏覽器的Console里嘗試一下,會(huì)發(fā)現(xiàn)exc2的用Promise.all執(zhí)行更快一些

image.png

兼容性

image.png

在自己的項(xiàng)目中使用

通過(guò) babel 來(lái)使用。

只需要設(shè)置 presets 為 stage-3 即可。

安裝依賴(lài):

npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime

修改.babelrc:

 "presets": ["es2015", "stage-3"],

 "plugins": ["transform-runtime"]

這樣就可以在項(xiàng)目中使用 async 函數(shù)了。

推廣

最近做了美妝代購(gòu),保證正品隨便驗(yàn),感興趣的掃碼加微信


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 異步編程對(duì)JavaScript語(yǔ)言太重要。Javascript語(yǔ)言的執(zhí)行環(huán)境是“單線(xiàn)程”的,如果沒(méi)有異步編程,根本...
    呼呼哥閱讀 7,333評(píng)論 5 22
  • 原文連接:https://blog.csdn.net/sinat_17775997/article/details...
    小豆soybean閱讀 4,277評(píng)論 0 7
  • async 函數(shù) 含義 ES2017 標(biāo)準(zhǔn)引入了 async 函數(shù),使得異步操作變得更加方便。 async 函數(shù)是...
    huilegezai閱讀 1,271評(píng)論 0 6
  • Promise 對(duì)象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,727評(píng)論 1 56
  • 你一定覺(jué)得拖延和猶豫是人類(lèi)最合乎人情的弱點(diǎn),但是正因?yàn)樗虾跞饲椋瑳](méi)有明顯的危害,所以無(wú)形中耽誤了許多事情,因此而...
    淰簡(jiǎn)閱讀 1,099評(píng)論 0 0