You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Promise最佳实践:判断资源存在性用resolve(false)还是reject()?

嘿,咱们先揪出两种写法里的共同错误,再聊聊哪种思路更合理~

首先,两个isAuthorized函数的catch分支都写错了!你现在写的.catch(next(Boom.forbidden()))会立即执行next(Boom.forbidden())——不管Promise有没有报错,这完全不是你想要的逻辑。正确的写法应该是把它改成回调函数:.catch(() => next(Boom.forbidden())),这样只有当Promise被reject时才会触发授权失败的逻辑。

接下来拆解两种实现思路:

Way A:用reject表示「资源不存在」

这种思路把「资源不存在」定义为异常场景,用Promise的reject来传递状态。不过你的原写法有冗余,可以简化:

  • 在then里,直接throw错误就行,不需要return Promise.reject()——then中抛出的异常会自动转为rejected Promise
  • 多余的catch包装可以删掉,让错误直接传递到上层处理(重新包装错误在这里没有实际意义)

修正后的代码:

export const existsA = (id) => {
  return getSomethingById(id)
    .then((result) => {
      if (!result) {
        throw new Error('Resource does not exist');
      }
    });
};

exports.isAuthorizedA = (req, res, next) => {
  existsA(req.user.id)
    .then(() => next()) // 资源存在,正常进入下一个中间件
    .catch(() => next(Boom.forbidden())); // 资源不存在/查询失败,返回403
};

这种思路的优点是贴合Promise「错误优先」的设计范式,把所有异常情况(资源不存在、查询报错)统一用reject处理,上层只需要在catch里统一处理授权失败。

Way B:用resolve(true/false)表示存在状态

这种思路把「是否存在」当作正常业务结果,用resolve返回布尔值。同样可以简化原写法:

  • 直接返回!!result就能得到布尔值,不需要冗余的if判断
  • 同样可以删掉多余的catch错误包装

修正后的代码:

export const existsB = (id) => {
  return getSomethingById(id)
    .then((result) => !!result); // 直接返回布尔值,表示资源是否存在
};

exports.isAuthorizedB = (req, res, next) => {
  existsB(req.user.id)
    .then((exists) => {
      exists ? next() : next(Boom.forbidden());
    })
    .catch(() => next(Boom.forbidden())); // 处理查询过程中的异常
};

这种思路的优点是语义更直白:exists函数的作用就是返回「是否存在」的结果,而非抛出错误。如果后续有其他场景需要判断资源存在性但不触发错误,这种写法会更灵活。

哪种更「正确」?

两种思路都可行,核心看你的业务场景和代码风格:

  • 如果「资源不存在」在你的业务逻辑里属于异常情况(比如这个接口本就只对存在的用户开放),Way A的错误处理思路更符合Promise的设计意图。
  • 如果「资源不存在」是正常业务状态(比如需要在其他地方判断存在性而不报错),Way B的布尔值返回方式更灵活。

在你的授权场景下,个人更推荐Way A——因为授权失败本身就是异常流程,用reject传递状态更贴合逻辑。

内容的提问来源于stack exchange,提问作者Vivien Adnot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:33:51