您好,欢迎访问代理记账网站
移动应用 微信公众号 联系我们

咨询热线 -

电话 15988168888

联系客服
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

如何在Javascript中编写没有try-catch块的异步等待

ES7 Async / await允许我们作为开发人员编写看起来是同步的异步JS代码。在当前的JS版本中,我们将Promises引入,这使我们能够简化异步流程并避免回叫。

回调地狱是一个术语,用于描述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....
          });
      });
   });
}

这使得维护代码和管理控制流程变得非常困难。只要想一想if语句,如果callbackA的某些结果等于'foo',则该语句需要执行其他Async方法。

营救承诺

有了promise和ES6,我们可以将以前的代码梦simplify简化为以下内容:

function asyncTask(cb) {

   asyncFuncA.then(AsyncFuncB)
      .then(AsyncFuncC)
      .then(AsyncFuncD)
      .then(data => cb(null, data)
      .catch(err => cb(err));
}

看起来好多了,您不觉得吗?

但是在现实世界中,异步流程可能会变得有些复杂,例如,在服务器模型(nodejs)中,您可能希望将一个实体保存到数据库,然后根据保存的值查找其他一些实体(如果该值存在) ,执行其他一些异步任务,在所有任务完成后,您可能希望使用步骤1中创建的对象对用户进行响应。并且,如果在其中一个步骤中发生错误,则要通知用户确切的错误。

有了当然的承诺,与普通的回调相比,它看起来要干净得多,但是,仍然会有点混乱恕我直言。

ES7异步/等待

注意:您需要使用转译器才能享受异步/等待,可以将babel或打字稿用于所需的polyfills。

那是我发现异步等待真正有用的地方,它允许您编写如下代码:

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);
}

上面的代码看起来更简洁,但是错误处理呢?

进行异步调用时,在执行Promise期间可能会发生某些情况(数据库连接错误,数据库模型验证错误等)。

由于异步函数正在等待Promises,因此当Promise遇到错误时,它将引发一个异常,该异常将在Promise的catch方法内捕获。

在异步/等待功能中,通常使用try / catch块来捕获此类错误。

我不是来自打字语言的背景,因此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);
}

一种不同的做事方式

最近,我一直在使用go-lang进行编码,非常喜欢他们的解决方案,如下所示:

data, err := db.Query("SELECT ...")
if err != nil { return err }

我认为这比使用try-catch块更干净,并且更少地对代码进行聚类,这使其可读性和可维护性更高。

但是await的问题是,如果没有为它提供try-catch块,它将静默退出您的函数。除非提供catch子句,否则您将无法控制它。

当我和Tomer Barnea的一个我的好朋友坐在一起,试图寻找更清洁的解决方案时,我们使用了以下方法:

还记得等待正在等待解决的诺言吗?

有了这些知识,我们可以制作小的实用程序函数来帮助我们捕获这些错误:

// 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() {
     let err, user, savedTask;

     [err, user] = await to(UserModel.findById(1));
     if(!user) throw new CustomerError('No user found');

     [err, savedTask] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
     if(err) throw new CustomError('Error occurred while saving task');

    if(user.notificationsEnabled) {
       const [err] = await to(NotificationService.sendNotification(user.id, 'Task Created'));  
       if (err) console.error('Just log the error and continue flow');
    }
}

上面的示例只是该解决方案的一个简单用例,您可以在to.js方法内附加拦截器,该方法将接收原始错误对象,对其进行记录或在将其传回之前进行任何必要的处理。

这篇文章只是查看异步/等待错误处理的另一种方式。不应将它用作您编写的每个异步/等待函数的goto,并且在很多情况下,将单个catch放在顶部就可以了。有时我们不想公开模型实现的错误对象,而是想提供一个掩盖底层猫鼬错误实现的自定义错误对象。

我们为此库创建了一个简单的NPM软件包,您可以使用以下程序进行安装:
Github Repo

npm i await-to-js

转自https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进