ES7 Async/await允许开发人员编写看起来是同步的异步JS代码。在此之前ES6中引入Promises,这使得我们简化Async流,并避免了回调地狱。
回调地狱是一个术语,用于描述JS中的以下情况:
function AsyncTask() {
asyncFuncA(function(err, resultA){
if(err) return cb(err);
asyncFuncB(function(err, resultB){
if(err) return cb(err);
asyncFuncC(function(err, resultC){
if(err) return cb(err);
// And so it goes....
});
});
});
}
这使得难以维护代码和管理控制流非常困难。
Promises出现
ES6中引入了Promises,可以将以前的代码噩梦简化为:
function asyncTask(cb) {
asyncFuncA.then(AsyncFuncB)
.then(AsyncFuncC)
.then(AsyncFuncD)
.then(data => cb(null, data)
.catch(err => cb(err));
}
但在实际场景中,Async流可能会变得有些复杂。
ES7 Async/await
注意:需要使用转换器才能享受Async/await,您可以使用babel或typescript来填充所需的polyfill。
它允许你编写这样的代码:
async function asyncTask(cb) {
const user = await UserModel.findById(1);
if(!user) return cb('No user found');
const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});
if(user.notificationsEnabled) {
await NotificationService.sendNotification(user.id, 'Task Created');
}
if(savedTask.assignedUser.id !== user.id) {
await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you');
}
cb(null, savedTask);
}
上面的代码看起来更清晰,但是,错误处理呢?
在async/await函数中,通常使用try/catch块来捕获此类错误。所以前面的代码看起来像这样:
async function asyncTask(cb) {
try {
const user = await UserModel.findById(1);
if(!user) return cb('No user found');
} catch(e) {
return cb('Unexpected error occurred');
}
try {
const savedTask = await TaskModel({userId: user.id, name: 'Demo Task'});
} catch(e) {
return cb('Error occurred while saving task');
}
if(user.notificationsEnabled) {
try {
await NotificationService.sendNotification(user.id, 'Task Created');
} catch(e) {
return cb('Error while sending notification');
}
}
if(savedTask.assignedUser.id !== user.id) {
try {
await NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you');
} catch(e) {
return cb('Error while sending notification');
}
}
cb(null, savedTask);
}
有没有更简洁的解决方案呢?
// to.js
export default function to(promise) {
return promise.then(data => {
return [null, data];
})
.catch(err => [err]);
}
函数接收一个promise,然后使用返回数据作为第二项解析对数组的成功响应。并且从第一个接收到的错误。
然后我们可以使异步代码看起来像这样:
import to from './to.js';
async function asyncTask(cb) {
let err, user, savedTask;
[err, user] = await to(UserModel.findById(1));
if(!user) return cb('No user found');
[err, savedTask] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
if(err) return cb('Error occurred while saving task');
if(user.notificationsEnabled) {
const [err] = await to(NotificationService.sendNotification(user.id, 'Task Created'));
if(err) return cb('Error while sending notification');
}
cb(null, savedTask);
}
上面的例子只是解决方案的一个简单用例,你可以在to.js方法中附加拦截器,该方法将接收原始错误对象,记录它或者在传回之前做任何你需要做的事情。
我们为这个库创建了一个简单的NPM包await-to-js,你可以使用它来安装它:
npm i await-to-js
来源:https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/
网友评论