Async/await
是 ES7 中的新特性虐秦,它可以讓開發(fā)者編寫異步代碼像同步代碼一樣,它的優(yōu)勢我們通過 Async/Await 這篇文章來了解刮便。
的確它給我們帶來了很多方便的地方睛藻,但是在 async/await
中如何來處理錯誤呢则北?在異步的調用中,會產生各種不同的錯誤呐能,例如:HTTP 請求產生了錯誤念搬、訪問 DB 產生的異常、操作文件產生異常摆出。在 Promise
的使用中锁蠕,當承諾遇到了錯誤,它會拋出一個異常懊蒸,該異常將被捕獲到一個方法回調中荣倾。在 async/await
中,我們又如何處理呢骑丸,當然很多人會回答:使用 try/catch
來捕獲這些錯誤舌仍,這樣一來代碼會看起來像這樣:
async function asyncFunc() {
try {
const product = await Api.product({ id : 10 });
if(!product) {
console.log('No product found');
}
}
catch(err) {
console.log(err);
}
try {
const saveProduct = await Api.save({
id: product.id,
name: product.name
});
}
catch(err) {
console.log(err);
}
}
回顧上面的代碼,try/catch
的確可以來解決錯誤異常的處理通危,但是讓代碼非常的不干凈铸豁,原本 async/await
的優(yōu)勢就是讓代碼更佳的簡約,這樣一來又違背了它的初中菊碟,這讓我們進入了新的思考节芥。
Go-lang 的靈感
在 Go 語言中處理異常的方式是這樣的:
f, err := os.Open("filename.txt")
if err != nil { return err }
它看起來要比繁多的 try/catch
更佳的干凈,并且讓代碼更佳容易閱讀逆害。我們是不是可以把這種語法運用到 async/await
中去呢头镊,但是讓人失望的是 async/await 如果產生了錯誤會立即退出你的函數,除非用 try/catch
魄幕,否則你無法控制它相艇。
但是沒有我們聰明的工程師無法辦到的事情,Dima 和他的小伙伴利用 Promise 來解決了這個問題:
// to.js
export default function to(promise) {
return promise.then(data => {
return [null, data];
})
.catch(err => [err]);
}
這一個工具方法接收一個承諾纯陨,讓后將異步獲取到的數據作為返回數組
的第二個值坛芽,捕捉到的錯誤作為返回數組
第一個值。然后我們的異步代碼會變成這樣:
import to from './to.js';
async function asyncFunc() {
let err, product, saveProduct;
[err, product] = await to(Api.product({ id : 10 }));
if(!product) {
console.log('No product found');
}
[err, saveProduct] = await to(Api.save({
id: product.id,
name: product.name
}));
if(err) {
console.log(err);
}
}
由此一來翼抠,async/await
又回到了最初的簡潔咙轩。
await-to-js
最后給 await-to-js
點一個贊,它很好的將這一工具封裝成了模塊阴颖,你可以通過 npm 來安裝它活喊,源碼地址:https://github.com/scopsy/await-to-js ,代碼其實很少膘盖,用 Typescript 寫的胧弛,小功能大作用尤误。
/**
* @param { Promise } promise
* @param { Object= } errorExt - Additional Information you can pass to the err object
* @return { Promise }
*/
export function to<T, U = any>(
promise: Promise<T>,
errorExt?: object
): Promise<[U | null, T | undefined]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, undefined]>(err => {
if (errorExt) {
Object.assign(err, errorExt)
}
return [err, undefined]
})
}
export default to