如何优雅地退出函数

退出函数怎么写?有人会说一个 return 就退出函数了,有这么简单吗?来看一个表单校验和提交结果的函数:

js 复制代码
// 表单校验
function validate() {}
// 提交表单
function submit() {
  validate();// ?如果表单校验失败怎么退出函数呢?
  fetch("/api/submit", {
    // ...
  });
}

如果表单校验失败怎么退出函数呢?传统的思维方式必然是使用return解决,让 validate 函数返回一个值来判断是退出函数还是继续执行:

diff 复制代码
function validate() {}
function submit() {
+  if (!validate()) {
+    return;
+  }
  fetch("/api/submit", {
    // ...
  });
}

这样解决是可以的,但是不够优雅,为什么呢?因为 validate 函数本身是不需要返回值的,现在却为了功能必须添加一个返回值,并且 submit 函数还依赖于 validate 的返回值,增加了函数之间的耦合度。如何优雅地退出函数,这就是今天的主题。

抛出异常

第一个方法当然是抛出异常,这一招我屡试不爽,还是上面那个案例,先看看如何通过抛出异常退出函数:

diff 复制代码
// 表单校验
function validate() {
+    throw new Error("验证失败");
}
// 提交表单
function submit() {
  validate();// ?如果表单校验失败怎么退出函数呢?
  fetch("/api/submit", {
    // ...
  });
}

如果 submit 还有其他很多流程并且这些流程中的某个分支也需要退出整个 submit 函数,使用抛出异常退出函数的话就不需要写那么多的 if else 了,例如:

js 复制代码
// 提交表单
function submit() {
  validate();// ?如果表单校验失败怎么退出函数呢?
  doSomething1(); 
  doSomething2();
  fetch("/api/submit", {
    // ...
  });
}

但是这种方式也有一个弊端,那就是带来了控制台的爆红,不过一看就看得出来这不是程序报错导致的,是我们手动抛出的:

抛出异常这种方式在异步函数中同样适用,但是需要改变写法,先来看看不改变写法会怎么样:

diff 复制代码
+ async function validate() {
  throw new Error("validate failed");
}
+ async function submit() {
  validate();
  fetch("/api/submit", {
    // ...
  });
}

咦,为什么抛出异常不生效了呢,要解答这个问题,首先得把这段代码"翻译"一下:

diff 复制代码
function validate() {
+  return Promise.reject(new Error("validate failed"));
}

显然这里函数没有真正抛出异常,而是被 Promise 拦截掉了,导致退出函数失败。这里只需要增加一个 await 就可以退出函数了:

diff 复制代码
async function submit() {
+  await validate();
  fetch("/api/submit", {
    // ...
  });
}

异步函数 reject

上面说了抛出异常可以退出异步函数,但是不仅仅这一种方式,还可以通过 Promise.reject 退出异步函数:

diff 复制代码
async function validate() {
  return Promise.reject();
}

所以如果想退出函数可以先将函数改为 async 函数,然后返回一个 reject 状态的 Promise,这样就能够退出函数了。

最后,总结一下所有退出函数的方法:

  1. 函数返回一个布尔值,根据这个布尔值判断是否 return 退出函数
  2. 抛出异常退出函数,注意异步函数需要加上 await,否则无法退出
  3. 将普通函数转为异步函数,然后返回一个 reject 状态的 Promise,也可以实现退出函数的目的
相关推荐
苏打水com4 小时前
第九篇:Day25-27 Vue进阶——组件复用与状态管理(对标职场“复杂项目”需求)
前端·javascript·vue.js
PineappleCoder4 小时前
别让页面 “鬼畜跳”!Google 钦点的 3 个性能指标,治好了我 80% 的用户投诉
前端·性能优化
卤代烃4 小时前
🕹️ [AI] Chrome DevTools MCP 原理分析
前端·mcp
梦里不知身是客114 小时前
flink对于迟到数据的处理
前端·javascript·flink
卤代烃5 小时前
🤝 了解 CDP (Chrome DevTools Protocol):browser-use 背后的隐藏功臣
前端·chrome·puppeteer
一 乐5 小时前
人事管理系统|基于Springboot+vue的企业人力资源管理系统设计与实现(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·后端
b***74885 小时前
前端状态系统的时代变革:从本地状态到全局状态,再到智能状态的未来趋势
前端·状态模式
愤怒的代码5 小时前
Java 面试 100 题深度解析 · 专栏总览与大纲
java·面试
秋氘渔5 小时前
Vue 3 组合式API中的生命周期钩子函数介绍
前端·javascript·vue.js
拉不动的猪5 小时前
requestAnimationFrame 与 JS 事件循环:宏任务执行顺序分析
前端·javascript·面试