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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32536049/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 10:33:36  来源:igfitidea点击:

Do I need to return after early resolve/reject?

javascriptpromisees6-promise

提问by sam

Suppose I have the following code.

假设我有以下代码。

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

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

  resolve(numerator / denominator);

 });
}

If my aim is to use rejectto exit early, should I get into the habit of returning immediately afterward as well?

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

回答by Ori Drori

The returnpurpose is to terminate the execution of the function after the rejection, and prevent the execution of the code after it.

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);
  });
}

In this case it prevents the resolve(numerator / denominator);from executing, which is not strictly needed. However, it's still preferable to terminate the execution to prevent a possible trap in the future. In addition, it's a good practice to prevent running code needlessly.

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

Background

背景

A promise can be in one of 3 states:

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

  1. pending - initial state. From pending we can move to one of the other states
  2. fulfilled - successful operation
  3. rejected - failed operation
  1. 待定 - 初始状态。从待定我们可以移动到其他状态之一
  2. 完成 - 成功操作
  3. 拒绝 - 失败的操作

When a promise is fulfilled or rejected, it will stay in this state indefinitely (settled). So, rejecting a fulfilled promise or fulfilling a rejected promise, will have not effect.

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

This example snippet shows that although the promise was fulfilled after being rejected, it stayed rejected.

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

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));

So why do we need to return?

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

Although we can't change a settled promise state, rejecting or resolving won't stop the execution of the rest of the function. The function may contain code that will create confusing results. For example:

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

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));

Even if the function doesn't contain such code right now, this creates a possible future trap. A future refactor might ignore the fact that the code is still executed after the promise is rejected, and will be hard to debug.

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

Stopping the execution after resolve/reject:

解决/拒绝后停止执行:

This is standard JS control flow stuff.

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

  • Return after the resolve/ reject:
  • resolve/后返回reject

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

    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

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

  • Return with the resolve/ reject- since the return value of the callback is ignored, we can save a line by returning the reject/resolve statement:
  • resolve/ reject- 返回,因为回调的返回值被忽略,我们可以通过返回reject/resolve语句来保存一行:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      return 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));

  • Using an if/else block:
  • 使用 if/else 块:

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

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

I prefer to use one of the returnoptions as the code is flatter.

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

回答by sam

A common idiom, which may or may not be your cup of tea, is to combine the returnwith the reject, to simultaneously reject the promise and exit from the function, so that the remainder of the function including the resolveis not executed. If you like this style, it can make your code a bit more compact.

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

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

This works fine because the Promise constructor does nothing with any return value, and in any case resolveand rejectreturn nothing.

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

The same idiom can be used with the callback style shown in another answer:

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

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

Again, this works fine because the person calling dividedoes not expect it to return anything and does not do anything with the return value.

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

回答by user2864740

Technicallyit is not needed here1- because a Promise can be resolved orrejected, exclusivelyand only once. The first Promise outcome wins and every subsequent result is ignored. This is differentfrom Node-style callbacks.

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

That being said it is good clean practiceto ensure that exactly one is called, when practical, and indeed in this case since there is no further async/deferred processing. The decision to "return early" is no different than ending any function when its work is complete- vs. continuing unrelated or unnecessary processing.

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

Returning at the appropriate time (or otherwise using conditionals to avoid executing the "other" case) reduces the chance of accidentally running code in an invalid state or performing unwanted side-effects; and as such it makes code less prone to 'breaking unexpectedly'.

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



1This technicallyanswer also hinges on the fact that in this casethe code after the "return", should it be omitted, will not result in a side-effect. JavaScript will happilydivide by zero and return either +Infinity/-Infinity or NaN.

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

回答by Benjamin H

If you don't "return" after a resolve/reject, bad things (like a page redirect) can happen after you meant for it to stop. Source: I ran into this.

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

回答by Benjamin Gruenbaum

The answer by Ori already explains that it is not necessary to returnbut it is good practice. Note that the promise constructor is throw safe so it will ignore thrown exceptions passed later in the path, essentially you have side effects you can't easily observe.

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

Note that returning early is also very common in callbacks:

请注意,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.
} 

So, while it is good practice in promises it is requiredwith callbacks. Some notes about your code:

因此,虽然在 Promise 中这是一种很好的做法,但它需要回调。关于您的代码的一些说明:

  • Your use case is hypothetical, don't actually use promises with synchronous actions.
  • The promise constructor ignoresreturn values. Some libraries will warn if you return a non-undefined value to warn you against the mistake of returning there. Most aren't that clever.
  • The promise constructor is throw safe, it will convert exceptions to rejections but as others have pointed out - a promise resolves once.
  • 您的用例是假设的,实际上不要将承诺与同步操作一起使用。
  • 承诺构造函数忽略返回值。如果您返回一个非未定义的值,一些库会发出警告,以警告您返回那里的错误。大多数都没有那么聪明。
  • 承诺构造函数是抛出安全的,它将异常转换为拒绝,但正如其他人指出的那样 - 承诺解决一次。

回答by Dorad

In many cases it is possible to validate parameters separately and immediately return a rejected promise with Promise.reject(reason).

在许多情况下,可以单独验证参数并立即使用Promise.reject(reason)返回被拒绝的承诺。

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


divide2(4, 0).then((result) => console.log(result), (error) => console.log(error));