如何在没有try-catch块的情况下编写async await

2019-05-2449次阅读javascriptvue

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/

上一篇: Promise的“Uncaught (in promise) …”错误  下一篇: async/ await结合Promise使用,如何接住Promise抛出的错误  

如何在没有try-catch块的情况下编写async await相关文章