ES7的async/await語法在2016年就已經提出來了,慚愧的是我最近才接觸使用,,下面來聊聊express
在async/await以前,咱們有三種方式寫異步代碼npm
嵌套回調promise
以Promise爲主的鏈式回調瀏覽器
使用Generatorsbash
可是,這三種寫起來都不夠優雅,ES7作了優化改進,async/await應運而生,async/await相比較Promise 對象then 函數的嵌套,與 Generator 執行的繁瑣(須要藉助co才能自動執行,不然得手動調用next() ), Async/Await 可讓你輕鬆寫出同步風格的代碼同時又擁有異步機制,更加簡潔,邏輯更加清晰。babel
async/await更加語義化,async 是「異步」的簡寫,async function 用於申明一個 function 是異步的; await,能夠認爲是async wait的簡寫, 用於等待一個異步方法執行完成;異步
async/await是一個用同步思惟解決異步問題的方案(等結果出來以後,代碼纔會繼續往下執行)async
能夠經過多層 async function 的同步寫法代替傳統的callback嵌套函數
自動將常規函數轉換成Promise,返回值也是一個Promise對象優化
只有async函數內部的異步操做執行完,纔會執行then方法指定的回調函數
異步函數內部可使用await
async function name([param[, param[, ... param]]]) { statements }
name: 函數名稱。
param: 要傳遞給函數的參數的名稱
statements: 函數體語句。
返回值: 返回的Promise對象會以async function的返回值進行解析,或者以該函數拋出的異常進行回絕。
複製代碼
await 放置在Promise調用以前,await 強制後面點代碼等待,直到Promise對象resolve,獲得resolve的值做爲await表達式的運算結果
await只能在async函數內部使用,用在普通函數裏就會報錯
[return_value] = await expression;
expression: 一個 Promise 對象或者任何要等待的值。
返回值:返回 Promise 對象的處理結果。若是等待的不是 Promise 對象,則返回該值自己。
複製代碼
在async函數裏,不管是Promise reject的數據仍是邏輯報錯,都會被默默吞掉,因此最好把await放入try{}catch{}中,catch可以捕捉到Promise對象rejected的數據或者拋出的異常
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模擬出錯,返回error
});
}
async function asyncPrint(ms) {
try {
console.log('start');
await timeout(ms); //這裏返回了錯誤
console.log('end'); //因此這句代碼不會被執行了
} catch(err) {
console.log(err); //這裏捕捉到錯誤error
}
}
asyncPrint(1000);
複製代碼
若是不用try/catch的話,也能夠像下面這樣處理錯誤(由於async函數執行後返回一個promise)
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模擬出錯,返回error
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms)
console.log('end'); //這句代碼不會被執行了
}
asyncPrint(1000).catch(err => {
console.log(err); // 從這裏捕捉到錯誤
});
複製代碼
若是你不想讓錯誤中斷後面代碼的執行,能夠提早截留住錯誤,像下面
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, ms); //reject模擬出錯,返回error
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms).catch(err => { // 注意要用catch
console.log(err)
})
console.log('end'); //這句代碼會被執行
}
asyncPrint(1000);
複製代碼
多個await命令的異步操做,若是不存在依賴關係(後面的await不依賴前一個await返回的結果),用Promise.all()讓它們同時觸發
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(); // 不依賴 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 的兩個並列await的寫法,比較耗時,只有test1執行完了纔會執行test2
你能夠在瀏覽器的Console裏嘗試一下,會發現exc2的用Promise.all執行更快一些
在本身的項目中使用
經過 babel 來使用。
只須要設置 presets 爲 stage-3 便可。
安裝依賴:
npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime
修改.babelrc:
"presets": ["es2015", "stage-3"],
"plugins": ["transform-runtime"]
複製代碼
這樣就能夠在項目中使用 async 函數了。