ES7的async/await語(yǔ)法在2016年就已經(jīng)提出來(lái)了,慚愧的是我最近才接觸使用,,下面來(lái)聊聊
解決了什么問(wèn)題
在async/await之前,我們有三種方式寫(xiě)異步代碼
嵌套回調(diào)
以Promise為主的鏈?zhǔn)交卣{(diào)
使用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)
async/await更加語(yǔ)義化,async 是“異步”的簡(jiǎn)寫(xiě),async function 用于申明一個(gè) function 是異步的; await,可以認(rèn)為是async wait的簡(jiǎn)寫(xiě), 用于等待一個(gè)異步方法執(zhí)行完成;
async/await是一個(gè)用同步思維解決異步問(wèn)題的方案(等結(jié)果出來(lái)之后,代碼才會(huì)繼續(xù)往下執(zhí)行)
可以通過(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)行回絕。
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ì)象,則返回該值本身。
錯(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í)行更快一些
兼容性
在自己的項(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),感興趣的掃碼加微信