在面試的時候,async/await
是很能看出應試者知識面的一個點。固然本身也沒想好從什麼角度去闡釋這個知識點。當面試管問的時候,你能夠答自執行的generator的語法糖。可是本身有些過實現麼,或者是看過他的實現。面試
注:對於generator不瞭解的,能夠先去看一下generator,順帶能夠把iterator看了。promise
ex代碼:babel
async function t() {
const x = await getResult();
const y = await getResult2();
return x + y;
}
複製代碼
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this, args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function t() {
return _t.apply(this, arguments);
}
function _t() {
_t = _asyncToGenerator(function* () {
const x = yield getResult();
const y = yield getResult2();
return x + y;
});
return _t.apply(this, arguments);
}
複製代碼
從代碼中能夠看出,babel將一個generator轉化爲async用了兩步_asyncToGenerator
和asyncGeneratorStep
。app
_asyncToGenerator
幹了什麼一、調用_asyncToGenerator
返回了一個promise,恰好符合async函數能夠接then的特性。異步
二、定義了一個成功的方法_next
,定義了一個失敗的方法_throw
。兩個函數中是調用asyncGeneratorStep
。看完asyncGeneratorStep
就知道這實際上是一個遞歸。async
三、執行_next
。也就是上面說的自執行的generator。函數
asyncGeneratorStep
幹了什麼一、try-catch去捕獲generator執行過程當中的錯誤。若是有報錯,async函數直接是reject狀態。優化
二、判斷info中的done值,是否爲true,爲true就表明迭代器已經執行完畢了,能夠將value值resolve出去。反之,則繼續調用_next
將值傳遞到下一個去。ui
這裏我惟一沒有看明白的是`_throw`,這個看代碼像是執行不到的。promise.resolve狀態值應該是fulfilled。看懂的能夠在評論中和我說一下,感謝。 this
每當一種新的語法糖出現,一定是彌補上一代解決方案的缺陷。
ex:
promise的出現,是爲了去避免callback hell
,避免的方式就是鏈式調用。
那async/await爲了去解決什麼呢?
async/await更貼近於同步性的風格,而promise則是用then的方式,於async/await相比,代碼會變多,並且async/await和同步函數差異不大,promise則寫法上仍是有差距的。
promise版
function getData() {
getRes().then((res) => {
console.log(res);
})
}
複製代碼
async/await版
const getData = async function() {
const res = await getRes();
console.log(res);
}
複製代碼
用promise的時候會發現,多個promise串行的時候,後面的promise須要去獲取前面promise的值是很是困難的。而async剛好解決了這個點。
const morePromise = () => {
return promiseFun1().then((value1) => {
return promiseFun2(value1).then((value2) => {
return promiseFun3(value1, value2).then((res) => {
console.log(res);
})
})
})
}
複製代碼
上面是嵌套版本的,可能根據不一樣的需求能夠不嵌套的。
const morePromise = () => {
return promiseFun1().then((value1) => {
return promiseAll([value1, promiseFun2(value1)])
}).then(([value1, value2]) => {
return promiseFun3(value1, value2).then((res) => {
console.log(res);
})
})
}
複製代碼
少了嵌套層級,可是仍是不盡如人意。
const morePromise = async function() {
const value1 = await promiseFun1();
const value2 = await promiseFun2(value1);
const res = await promiseFun3(value1, valuw2);
return res;
}
複製代碼
串行的異步流程,一定會有中間值的牽扯,因此async/await的優點就很明顯了。
好比,目前有個需求,你請求完一個數據以後,再去判斷是否還須要請求更多數據。用promise去實現仍是會出現嵌套層級。
const a = () => {
return getResult().then((data) => {
if(data.hasMore) {
return getMoreRes(data).then((dataMore) => {
return dataMore;
})
} else {
return data;
}
})
}
複製代碼
可是用async去優化這個例子的話,能使代碼更加優美。
const a = async() => {
const data = await getResult();
if(data.hasMore) {
const dataMore = await getMoreRes(data);
return dataMore;
} else {
return data;
}
}
複製代碼
上面咱們講了幾點async/await的優點所在,可是async/await也不是萬能的。上面清一色的是講串聯異步的場景。當咱們變成並聯異步場景時。仍是須要藉助於promise.all來實現
const a = async function() {
const res = await Promise.all[getRes1(), getRes2()];
return res;
}
複製代碼
async/await在錯誤捕獲方面主要使用的是try-catch。
const a = async () => {
try{
const res = await Promise.reject(1);
} catch(err) {
console.log(err);
}
}
複製代碼
能夠抽離一個公共函數來作這件事情。由於每一個promise後面都去作catch的處理,代碼會寫的很冗長。
const a = async function() {
const res = await Promise.reject(1).catch((err) => {
console.log(err);
})
}
複製代碼
// 公共函數
function errWrap(promise) {
return promise().then((data) => {
return [null, data];
}).catch((err) => {
return [err, null];
})
}
複製代碼