首页 > 编程语言 >在 JavaScript 中编写Go式错误处理的async/await

在 JavaScript 中编写Go式错误处理的async/await

时间:2023-02-01 22:01:43浏览次数:63  
标签:JavaScript return err cb await user catch 错误处理

在 JavaScript 中编写Go式错误处理的async/await_async/await

ES7 引入 ​​async/await​​​ 允许开发人员编写看起来像同步的异步 JavaScript 代码。在当前的 JavaScript 版本中,还可以使用 ​​Promises​​,这些功能都是为了简化异步流程并避免回调地狱。

回调地狱是一个术语,用于描述 JavaScript 中的以下情况:

function asyncTasks() {
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);

// 更多...
});
});
});
}

上述代码使得维护代码和管理控制流变得非常困难。只需考虑一个 ​​if​​ 语句,如果 ​​callbackA​​ 的某些结果等于 ​​foo​​,则需要执行其他 ​​async​​ 方法。

拯救 Promises

借助 ​​promises​​ 和 ​​ES6​​,可以将之前代码的回调噩梦简化为如下内容:

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

虽然从代码阅读来看好很多。但在现实世界的场景中,异步流程可能会变得稍微复杂一些,例如在服务器模型 (​​nodejs​​ 编程)中,可能想要将一个实体数据保存到数据库中,然后根据保存的值查询其他一些实体,如果该值存在,执行其他一些异步任务,在所有任务完成后,可能想要用步骤 ​​1​​ 中创建的对象响应用户。如果在某个步骤中发生了错误,希望通知用户确切的错误。

当然,使用 ​​promises​​ 看起来会比使用普通回调更干净,但它仍然会变得有点混乱。

当然,使用 ​​promises​​ 看起来会比使用普通回调更干净,但它仍然会变得有点混乱。

关于 ​​Promise​​ 需要的了解的:

async/await

在 ECMAScript 2017 中添加了 ​​async/await​​ 关键字,并在主流脚本库和其他 JavaScript 编程中得到广泛的应用。

这就是 ​​async/await​​ 真正有用的地方,通过它可以编写下面的代码:

async function asyncTasks(cb) {
const user = await UserModel.findById(1);
if (!user) return cb("用户未找到");

const savedTask = await TaskModel({ userId: user.id, name: "DevPoint" });

if (user.notificationsEnabled) {
await NotificationService.sendNotification(user.id, "任务已创建");
}

if (savedTask.assignedUser.id !== user.id) {
await NotificationService.sendNotification(
savedTask.assignedUser.id,
"任务已为您创建"
);
}

cb(null, savedTask);
}

上面的代码看起来干净多了,但是错误处理还是存在不足。

进行异步调用时,在执行 ​​promise​​ 期间可能会发生某些事情(如数据库连接错误、数据库模型验证错误等)。由于 ​​async​​ 函数正在等待 ​​Promise​​,因此当 ​​Promise​​ 遇到错误时,它会抛出一个异常,该异常将在 ​​Promise​​ 的 ​​catch​​ 方法中被捕获。

在 ​​async/await​​ 函数中,通常使用 ​​try/catch​​ 块来捕获此类错误。

使用 ​​try/catch​​ 后代码如下:

async function asyncTasks(cb) {
try {
const user = await UserModel.findById(1);
if (!user) return cb("用户未找到");
} catch (error) {
return cb("程序异常:可能是数据库问题");
}

try {
const savedTask = await TaskModel({
userId: user.id,
name: "DevPoint",
});
} catch (error) {
return cb("程序异常:任务保存失败");
}

if (user.notificationsEnabled) {
try {
await NotificationService.sendNotification(user.id, "任务已创建");
} catch (error) {
return cb("程序异常:sendNotification 失败");
}
}

if (savedTask.assignedUser.id !== user.id) {
try {
await NotificationService.sendNotification(
savedTask.assignedUser.id,
"任务已为您创建"
);
} catch (error) {
return cb("程序异常:sendNotification 失败");
}
}

cb(null, savedTask);
}

个人对 ​​try/catch​​ 的使用不太喜欢,总觉得这种代码的使用是用于捕获无法预知的错误,比较喜欢 Go 的处理方式,当然这纯属个人观点。

优化 ​​try/catch​

在 Go 中的处理方式如下:

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

它比使用 ​​try/catch​​ 块更干净,并且更少地聚集代码,可读和可维护性更高。

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

利用 ​​await​​ 是在等待 ​​resolve​​ 的 ​​promise​​。下面可以制作小的效用函数来捕获这些错误:

function to(promise) {
return promise
.then((data) => {
return [null, data];
})
.catch((err) => [err]);
}

效用函数接收一个 ​​promise​​,然后将成功响应解析为一个数组,并将返回数据作为第二项,并且从捕获中收到的错误是第一个。

function to(promise) {
return promise
.then((data) => {
return [null, data];
})
.catch((err) => [err]);
}

async function asyncTask() {
let err, user, savedTask;

[err, user] = await to(UserModel.findById(1));
if (!user) throw new CustomerError("用户未找到");

[err, savedTask] = await to(
TaskModel({ userId: user.id, name: "DevPoint" })
);
if (err) throw new CustomError("程序异常:任务保存失败");

if (user.notificationsEnabled) {
const [err] = await to(
NotificationService.sendNotification(user.id, "任务已创建")
);
if (err) console.error("程序异常");
}
}

上面的示例只是该解决方案的一个简单用例,还可以在 ​​to​​ 方法中增加一个拦截器,接收原始错误对象,记录它或在将它传回之前做任何需要做的事情。

总结

本文介绍了 ​​async/await​​ 错误处理的另一种方式,不应该将其视为标准处理方式,因为在很多情况下有一个 ​​try/catch​​ 块就可以了。


标签:JavaScript,return,err,cb,await,user,catch,错误处理
From: https://blog.51cto.com/devpoint/6031441

相关文章

  • 1.1 JavaScript简介
    1.1.1JavaScript的基本概念JavaScript是一种解释性语言,也是一种基于对象(Object)和事件驱动(EventDriven)的、并具有安全性能的脚本语言。特点【1.JavaScript主要用来向......
  • JavaScript 数组去重
    JavaScript中有多种方法可以实现数组去重,下面是几种常用的方法:1、使用Set去重:Set数据结构中不能有重复元素,可以将数组转成Set类型,再转回数组。letarr=[1,2,3,4......
  • JavaScript之异步编程
    什么是异步异步:Asynchronous,async是与同步synchronous,sync相对的概念。传统单线程编程中,程序的运行是同步的,指程序运行在一个控制流之中运行。而异步的概念就是不保证同......
  • JavaScript闭包的概念
    什么是闭包?闭包有什么作用,缺点是什么?闭包的概念:JavaScript中函数会产生闭包(closure)。闭包是函数本身和该函数声明时所处的环境状态的组合;函数能够“记忆住”其定义......
  • JavaScript 输入一个数 返回 2数相乘 使得 2数尽可能接近
    functiongetRC(pageCount){vara=Math.round(Math.sqrt(pageCount));for(vari=0;i<10;i++){varb=pageCount/(a+i);if(b===Math.round(b))......
  • Ai JavaScript 把桌面下面 所有的png 图片导入到 ai里面的 脚本 获取某目录下所有文件
    vardoc=app.activeDocument;//创建一个目录varinput=newFolder("C:\\Users\\Administrator\\Desktop");//获取input目录下面的所有png图片得到一个数组对象vard......
  • Illustrator JavaScript 出血
    IllustratorJavaScript出血vardoc=app.activeDocument;varpt=72/25.4;varrc=1*pt;varls=6*pt;for(vari=0;i<doc.selection.length;i++){varshape=d......
  • JavaScript奇技淫巧:操控URL
    JavaScript奇技淫巧:操控URL本文展示两种不常见的JS编程技巧:实现操控浏览器窗口,更改父窗口和子窗口的URL地址。修改父窗口URL当使用window.open()打开一个窗口,可以用window.......
  • 面试官:你说说 JavaScript 中类型的转换机制
    前言面试官:“你说说JavaScript中类型的转换机制”紧张的萌新:“字符串跟其他类型拼接会变成字符串...”面试官:“...”······大家好,我是CoderBin。又来到了面试官......
  • JavaScript 中更安全的 URL 读写
    前言URL对于我们开发人员来讲,应该是非常熟悉了。在对URL进行参数拼接时,我们一般都会直接进行字符串拼接或使用模版字符串,因为这样非常方便,但是我们这样其实会在不知不觉中......