扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
本篇内容主要讲解“ javascript中Dima去除try-catch的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“ javascript中Dima去除try-catch的方法是什么”吧!
创新互联长期为近1000家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为卓尼企业提供专业的网站设计、成都网站制作,卓尼网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。
Dima 去除 try-catch 的方法
当然套路依旧,Dima 讲到了回调地狱,Promise 链并最终引出了 async/await。而在处理错误的时候,他并不喜欢 try-catch 的方式,所以写了一个 to(promise) 来对 Promise 进行封装,辅以解构语法,实现了同步写法但类似 Node 错误标准的代码。摘抄代码如下
// to.js export default function to(promise) { return promise .then(data => { return [null, data]; }) .catch(err => [err]); }
应用示例:
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); }
Dima 的办法让人产生的了熟悉的感觉,Node 的回调中不是经常都这样写吗?
(err, data) => { if (err) { // deal with error } else { // deal with data } }
所以这个方法真的很有意思。不过回过头来想一想,这段代码中每当遇到错误,都是将错误消息通过 cb() 调用推出去,同时中断后续过程。像这种中断式的错误处理,其实正适合采用 try-catch。
使用 try-catch 改写上面的代码
要用 try-catch 改写上面的代码,首先要去掉 to() 封装。这样,一旦发生错误,需要使用 Promise.prototype.catch() 进行捕捉,或者使用 try-catch 对 await promise 语句进行捕捉。捕捉到的,当然是每个业务代码里 reject 出来的 err。
然而注意,上面的代码中并没有直接使用 err,而是使用了自定义的错误消息。所以需要对 reject 出来的 err 进一步处理成指定的错误消息。当然这难不到谁,比如
someAsync().catch(err => Project.reject("specified message"));
然后再最外层加上 try-catch 就好。所以改写之后的代码是:
async function asyncTask(cb) { try { const user = await UserModel.findById(1) .catch(err => Promise.reject("No user found")); const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }) .catch(err => Promise.reject("Error occurred while saving task")); if (user.notificationsEnabled) { await NotificationService.sendNotification(user.id, "Task Created") .catch(err => Promise.reject("Error while sending notification")); } cb(null, savedTask); } catch (err) { cb(err); } }
上面这段代码,从代码量上来说,并没有比 Dima 的代码减少了多少工作量,只是去掉了大量 if (err) {} 结构。不习惯使用 try-catch 的程序员找找不到中断点,但习惯了 try-catch 的程序员都知道,业务过程中一旦发生错误(异步代码里指 reject),代码就会跳到 catch 块去处理 reject 出来的值。
但是,一般业务代码 reject 出来的信息通常都是有用的。假如上面的每个业务 reject 出来的 err 本身就是错误消息,那么,用 Dima 的模式,仍然需要写
if (err) return cb(err);
而用 try-catch 的模式,就简单多了
async function asyncTask(cb) { try { const user = await UserModel.findById(1); const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }); if (user.notificationsEnabled) { await NotificationService.sendNotification(user.id, "Task Created"); } cb(null, savedTask); } catch (err) { cb(err); } }
为什么?因为在 Dima 的模式中,if (err) 实际上处理了两个业务:一是捕捉会引起中断的 err ,并将其转换为错误消息,二是通过 return 中断业务过程。所以当 err 转换为错误消息这一过程不再需要的时候,这种捕捉中断再重新引起中断的处理主显得多余了。
继续改进
用函数表达式改善 try-catch 逻辑
当然还有改进的空间,比如 try {} 块中的代码比较长,会造成阅读不太方便,try-catch 的逻辑有被“切断”的感觉。这种情况下可以使用函数表达式来改善
async function asyncTask(cb) { async function process() { const user = await UserModel.findById(1); const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }); if (user.notificationsEnabled) { await NotificationService.sendNotification(user.id, "Task Created"); } return savedTask; } try { cb(null, await process()); } catch (err) { cb(err); } }
如果对错误的处理代码比较长,也可以写成单独的函数表达式。
如果过程中每一步的错误处理逻辑不同怎么办
如果发生错误,不再转换为错误消息,而是特定的错误处理逻辑,怎么办?
思考一下,我们用字符串来表示错误消息,以后可以通过 console.log() 来处理处理。而逻辑,最适合的表示当然是函数表达式,最终可以通过调用来进行统一处理
async function asyncTask(cb) { async function process() { const user = await UserModel.findById(1) .catch(err => Promise.reject(() => { // deal with error on looking for the user return "No user found"; })); const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }) .catch(err => Promise.reject(() => { // making model error // deal with it return err === 1 ? "Error occurred while saving task" : "Error occurred while making model"; })); if (user.notificationsEnabled) { await NotificationService.sendNotification(user.id, "Task Created") .catch(err => Promise.reject(() => { // just print a message logger.log(err); return "Error while sending notification"; })); } return savedTask; } try { cb(null, await process()); } catch (func) { cb(func()); } }
甚至还可以处理更复杂的情况
现在应该都知道 .catch(err => Promise.reject(xx)),这里的 xx 就是 try-catch 的 catch 块捕捉到的对象,所以如果不同的业务 reject 出来不同的对象,比如有些是函数(表示错误处理逻辑),有些是字符串(表示错误消息),有些是数字(表示错误代码)——其实只需要改 catch 块就行
try { // ... } catch(something) { switch (typeof something) { case "string": // show message something break; case "function": something(); break; case "number": // look up something as code // and show correlative message break; default: // deal with unknown error } }
到此,相信大家对“ javascript中Dima去除try-catch的方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流