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

Javascript 我是否需要在提前解决/拒绝后返回?,javascript,promise,es6-promise,Javascript,Promise,Es6 Promise,假设我有以下代码 function divide(numerator, denominator) { return new Promise((resolve, reject) => { if(denominator === 0){ reject("Cannot divide by 0"); return; //superfluous? } resolve(numerator / denominator); }); } 如果我的目标是使用reject提前退

假设我有以下代码

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

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

  resolve(numerator / denominator);

 });
}

如果我的目标是使用
reject
提前退出,我是否应该养成
return
ing的习惯?

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);
  });
}
在这种情况下,它阻止
解析(分子/分母)从执行开始,这不是严格需要的。但是,最好还是终止执行,以防止将来可能出现陷阱。此外,防止不必要地运行代码是一种很好的做法

背景

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

  • 挂起-初始状态。我们可以从待定状态转移到其他状态之一
  • 完成-成功运营
  • 拒绝-操作失败
  • 当一个承诺被履行或拒绝时,它将无限期地保持这种状态(已解决)。因此,拒绝履行承诺或履行被拒绝的承诺将无效

    这个示例片段显示,尽管承诺在被拒绝后得到了履行,但它仍然被拒绝

    函数除法(分子、分母){
    返回新承诺((解决、拒绝)=>{
    如果(分母===0){
    拒绝(“不能除以0”);
    }
    解析(分子/分母);
    });
    }
    除以(5,0)
    .then((result)=>console.log('result:',result))
    .catch((错误)=>console.log('error:',error))从技术上讲,此处不需要它1-因为承诺可以被唯一且仅一次地解决或拒绝。第一个承诺结果获胜,随后的每个结果都被忽略。这与节点样式回调不同

    也就是说,在实际情况下,确保只调用一个是一种良好的干净实践,在这种情况下确实如此,因为没有进一步的异步/延迟处理决定“提前返回”与在任何功能完成后结束该功能无异-与继续进行无关或不必要的处理无异

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



    1从技术上来说,这个答案还取决于这样一个事实:在这种情况下,如果省略“return”后面的代码,将不会产生副作用。JavaScript很乐意除以零并返回+Infinity/-Infinity或NaN。

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

    请注意,
    return
    ing 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.
    } 
    
    因此,虽然这是承诺中的良好实践,但回调也是必需的。关于代码的一些注释:

    • 您的用例是假设性的,不要实际使用同步动作的承诺
    • 承诺构造函数忽略返回值。如果返回未定义的值,某些库将发出警告,以警告您返回该值的错误。大多数人并不那么聪明
    • 承诺构造函数是抛出安全的,它会将异常转换为拒绝,但正如其他人所指出的,承诺只会解决一次
        一个常见的习惯用法,可能是你喜欢的,也可能不是你喜欢的,就是将
        返回
        拒绝
        结合起来,同时拒绝承诺并退出函数,这样包括
        解析
        在内的其余函数就不会执行。如果您喜欢这种风格,它可以使您的代码更加紧凑

        function divide(numerator, denominator) {
          return new Promise((resolve, reject) => {
            if (denominator === 0) return reject("Cannot divide by 0");
                                   ^^^^^^^^^^^^^^
            resolve(numerator / denominator);
          });
        }
        
        这很好,因为承诺构造函数不使用任何返回值,并且在任何情况下
        resolve
        reject
        都不返回任何值

        同样的习惯用法也可以用于另一个答案中所示的回调样式:

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

        同样,这也很好,因为调用divide的人不希望它返回任何东西,也不处理返回值。

        如果在解析/拒绝后不“返回”,则在您打算停止后可能会发生错误(如页面重定向)。来源:我遇到了这个问题。

        在许多情况下,可以单独验证参数,并立即返回拒绝的承诺

        函数除法2(分子、分母){
        如果(分母===0){
        返回承诺。拒绝(“不能除以0”);
        }
        返回新承诺((解决、拒绝)=>{
        解析(分子/分母);
        });
        }
        
        divide2(4,0)。然后((结果)=>console.log(结果),(错误)=>console.log(错误))值得注意的是,如果
        返回值
        存在或不存在,代码实际上不会有不同的行为,因为一旦设置了承诺状态,它就无法更改,因此在调用
        拒绝()
        后调用
        解析()
        除了使用一些额外的CPU周期外,不会执行任何操作。一、 从代码清洁度和效率的角度来看,我自己会使用
        return
        ,但在这个特定示例中不需要它。尝试使用
        Promise。尝试(()=>{})而不是新的Promise,并避免使用resolve/reject调用。相反,您可以只写
        返回分母===0?抛出“不能被零除”:分子/分母我使用
        承诺。尝试
        作为一种启动承诺的手段,同时消除包含在try/catch块中的有问题的承诺。知道这一点很好,我喜欢这种模式。然而,此时是一个0阶段的建议,因此您只能使用或使用承诺库,如bluebird或Q.@jfriend00,显然在这个简单的例子中