我需要在提前解决/拒绝后返回吗?

IT技术 javascript promise es6-promise
2021-01-30 07:59:10

假设我有以下代码。

function divide(numerator, denominator) {
 return new Promise((resolve, reject) => {

  if(denominator === 0){
   reject("Cannot divide by 0");
   return; //superfluous?
  }

  resolve(numerator / denominator);

 });
}

如果我的目标是使用reject早退出,我是否也应该养成使用后return立即退出的习惯

6个回答

return目的是拒绝后终止函数的执行,防止代码执行后它。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {

    if (denominator === 0) {
      reject("Cannot divide by 0");
      return; // The function execution ends here 
    }

    resolve(numerator / denominator);
  });
}

在这种情况下,它会阻止resolve(numerator / denominator);执行,这不是严格需要的。但是,最好还是终止执行以防止将来出现可能的陷阱。此外,防止不必要地运行代码也是一种很好的做法。

背景

Promise可以处于以下三种状态之一:

  1. 待定 - 初始状态。从待定我们可以移动到其他状态之一
  2. 完成 - 成功操作
  3. 拒绝 - 失败的操作

当一个Promise被履行或被拒绝时,它将无限期地保持在这个状态(已解决)。因此,拒绝已履行的Promise或履行已拒绝的Promise,都不会产生影响。

此示例代码段表明,虽然Promise在被拒绝后得到了履行,但它仍然被拒绝。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }

    resolve(numerator / denominator);
  });
}

divide(5,0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

那么我们为什么需要返回呢?

虽然我们不能改变一个已解决的Promise状态,但拒绝或解决不会停止函数其余部分的执行。该函数可能包含会产生混淆结果的代码。例如:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }
    
    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

即使函数现在不包含这样的代码,这也会造成未来可能的陷阱。未来的重构可能会忽略在 promise 被拒绝后代码仍在执行的事实,并且将难以调试。

解决/拒绝后停止执行:

这是标准的 JS 控制流的东西。

  • resolve/之后返回reject

  • resolve/ reject- 返回,因为回调的返回值被忽略,我们可以通过返回reject/resolve语句来保存一行:

  • 使用 if/else 块:

我更喜欢使用其中一个return选项,因为代码更扁平。

很高兴知道,我喜欢这种模式。但是,此时Promise.try是阶段 0 建议,因此您只能将其与shim或使用Promise库(例如 bluebird 或 Q)一起使用。
2021-03-17 07:59:10
尝试使用Promise.try(() => { })而不是 new Promise 并避免使用 resolve/reject 调用。相反,您可以编写return denominator === 0 ? throw 'Cannot divide by zero' : numerator / denominator; I usePromise.try作为启动 Promise 的一种方式,并消除包裹在有问题的 try/catch 块中的 Promise。
2021-03-20 07:59:10
@jfriend00 显然,在这个简单的示例中,代码的行为不会有所不同。但是,如果您在之后的代码reject做了一些昂贵的事情,例如连接到数据库或 API 端点,该怎么办?这一切都是不必要的,并且会花费您金钱和资源,尤其是当您连接到诸如 AWS 数据库或 API 网关端点之类的东西时。在这种情况下,您肯定会使用 return 以避免执行不必要的代码。
2021-03-25 07:59:10
@JakeWilson - 当然,这只是 Javascript 中的正常代码流,与Promise完全无关。如果您已完成对函数的处理并且不想在当前代码路径中执行更多代码,则插入一个return.
2021-03-28 07:59:10
值得注意的是,如果return存在或不存在,代码实际上不会有不同的行为,因为一旦设置了Promise状态,它就无法更改,因此调用resolve()后调用reject()除了使用一些额外的 CPU 周期外不会做任何事情。我自己会return从代码清洁度和效率的角度使用just,但在这个特定示例中不需要它。
2021-04-10 07:59:10

一个常见的习语,可能是也可能不是你的一杯茶,是将 thereturn与 the结合起来reject,同时拒绝 promise 并退出函数,这样包括 the 在内的函数的其余部分resolve不会被执行。如果你喜欢这种风格,它可以让你的代码更紧凑一些。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) return reject("Cannot divide by 0");
                           ^^^^^^^^^^^^^^
    resolve(numerator / denominator);
  });
}

因为无极构造方法不具有任何返回值,并且在任何情况下也能正常工作resolvereject任何回报。

相同的习语可以与另一个答案中显示的回调样式一起使用:

function divide(nom, denom, cb){
  if(denom === 0) return cb(Error("Cannot divide by zero"));
                  ^^^^^^^^^
  cb(null, nom / denom);
} 

同样,这工作正常,因为调用divide者不希望它返回任何内容,并且不会对返回值执行任何操作。

@TobyCaulk 如果人们需要了解 return 的作用,那么他们不应该玩 Promises,他们应该学习基本的编程。
2021-03-13 07:59:10
我不喜欢这个。这给人的感觉是你正在返回一些你实际上没有的东西。您正在调用拒绝函数,然后使用 return 结束函数执行。将它们分开放置,您所做的只会使人们感到困惑。代码可读性是王道。
2021-03-19 07:59:10
@KarlMorrison 个人意见!= 不好的做法。它可能会帮助新的 Javascript 开发人员了解返回的内容。
2021-03-20 07:59:10
@KarlMorrison 你实际上是在返回“某物”,一个被拒绝的Promise。我认为你所说的“概念”是非常个人化的。返回reject状态没有错
2021-04-04 07:59:10
@Frondor 我认为您没有理解我写的内容。你我当然明白这一点,在同一行返回拒绝时什么也不会发生。但是那些不太习惯将 JavaScript 引入项目的开发人员呢?这种类型的编程降低了这些人的可读性。今天的 JavaScript 生态系统已经一团糟,人们传播这种做法只会让情况变得更糟。这是不好的做法。
2021-04-10 07:59:10

如果您在解决/拒绝之后没有“返回”,那么在您打算停止之后可能会发生不好的事情(例如页面重定向)。来源:我遇到了这个。

+1 例如。我遇到了一个问题,我的程序会进行 100 多个无效的数据库查询,但我不知道为什么。结果我被拒绝后并没有“返回”。这是一个小错误,但我吸取了教训。
2021-03-31 07:59:10

技术上在这里不需要它1 -因为Promise可以解决或者拒绝,仅仅只有一次。第一个 Promise 结果获胜,随后的每个结果都将被忽略。这是不同的节点样式的回调。

话虽如此,但在可行的情况下,确保确切地调用一个是一种很好的清洁实践,实际上在这种情况下,因为没有进一步的异步/延迟处理。“提前返回”的决定与在其工作完成后结束任何功能没有什么不同- 与继续无关或不必要的处理。

在适当的时间返回(或以其他方式使用条件来避免执行“其他”情况)减少了意外在无效状态下运行代码或执行不需要的副作用的机会;因此,它使代码不太容易“意外中断”。


1技术上讲,这个答案也取决于这样一个事实,即在这种情况下,“返回”之后的代码如果被省略,将不会导致副作用。JavaScript 很乐意除以零并返回 +Infinity/-Infinity 或 NaN。

脚注不错!!
2021-03-23 07:59:10

Ori 的回答已经解释说没有必要,return但这是一种很好的做法。请注意,promise 构造函数是抛出安全的,因此它会忽略路径中稍后传递的抛出的异常,本质上您有无法轻易观察到的副作用。

请注意,returning early 在回调中也很常见:

function divide(nom, denom, cb){
     if(denom === 0){
         cb(Error("Cannot divide by zero");
         return; // unlike with promises, missing the return here is a mistake
     }
     cb(null, nom / denom); // this will divide by zero. Since it's a callback.
} 

因此,虽然在 Promise 中这是一个很好的实践,但回调必需的关于您的代码的一些说明:

  • 您的用例是假设的,实际上不要将Promise与同步操作一起使用。
  • Promise构造函数忽略返回值。如果您返回一个非未定义的值,一些库会发出警告,以警告您返回那里的错误。大多数都没有那么聪明。
  • Promise构造函数是抛出安全的,它将异常转换为拒绝,但正如其他人指出的那样 - Promise解决一次。