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

假设我有以下代码。

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


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


resolve(numerator / denominator);


});
}

如果我的目标是使用reject提前退出,我是否应该在之后立即养成returning的习惯?

125474 次浏览

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);的执行,这不是严格需要的。但是,最好还是终止执行,以防止将来可能出现陷阱。此外,防止运行不必要的代码是一个很好的实践。

背景

承诺可以是三种状态之一:

  1. Pending -初始状态。我们可以从待定状态转移到其他状态
  2. 圆满——成功运营
  3. 拒绝—操作失败

当一个承诺被履行或被拒绝时,它将无限期地保持这种状态。因此,拒绝一个已实现的承诺或履行一个已被拒绝的承诺,都不会有效果。

这个例子片段表明,虽然承诺在被拒绝后得到了实现,但它仍然被拒绝。

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

那我们为什么要回去呢?

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

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

即使函数现在不包含这样的代码,这也可能在将来创建一个陷阱。未来的重构可能会忽略这样一个事实,即在承诺被拒绝后代码仍在执行,并且很难调试。

执行完resolve/reject后停止执行:

这是标准的JS控制流。

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

  • 返回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));

  • 使用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));

我更喜欢使用return选项之一,因为代码更平坦。

从技术上讲在这里不需要。__abc1 -因为一个Promise可以被解析。第一个Promise结果获胜,随后的每个结果都被忽略。这是来自node样式回调的不同的

也就是说,它是良好的清洁实践,以确保在实际情况下,确切地说,在这种情况下,因为没有进一步的异步/延迟处理。决定“提前返回”与在函数完成工作时终止任何函数没有什么不同 vs.继续不相关或不必要的处理。

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


1这个从技术上讲的答案还取决于这样一个事实:在这种情况下在“return”之后的代码,如果它被省略,将不会导致副作用。JavaScript将幸福的除零并返回+∞/-∞或NaN。

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构造函数是throw安全的,它将异常转换为拒绝,但正如其他人指出的那样——一个promise只解决一次。

一个常见的习惯用法是将returnreject结合起来,同时拒绝承诺并退出函数,这样函数的其余部分(包括resolve)就不会被执行,这可能是你的菜,也可能不是你的菜。如果您喜欢这种风格,它可以使您的代码更加紧凑。

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

这工作得很好,因为Promise构造函数对任何返回值都不做任何操作,并且在任何情况下resolvereject都不返回任何值。

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

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

同样,这工作得很好,因为调用divide的人不期望它返回任何东西,也不对返回值做任何事情。

如果你在解决/拒绝后不“返回”,在你想要它停止后可能会发生糟糕的事情(比如页面重定向)。来源:我遇到了这种情况。

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

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