假设我有以下代码。
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if(denominator === 0){
reject("Cannot divide by 0");
return; //superfluous?
}
resolve(numerator / denominator);
});
}
如果我的目标是使用reject提前退出,那么我是否也应该养成立即返回的习惯呢?
一个常见的习惯用法(可能是你喜欢的,也可能不是)是将返回和拒绝结合起来,同时拒绝承诺并退出函数,这样函数的其余部分(包括resolve)就不会执行。如果您喜欢这种风格,它可以使您的代码更加紧凑。
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) return reject("Cannot divide by 0");
^^^^^^^^^^^^^^
resolve(numerator / denominator);
});
}
这工作得很好,因为Promise构造函数对任何返回值都不做任何操作,并且在任何情况下都不会解析和拒绝返回任何值。
同样的习语也可以用于另一个答案中显示的回调样式:
function divide(nom, denom, cb){
if(denom === 0) return cb(Error("Cannot divide by zero"));
^^^^^^^^^
cb(null, nom / denom);
}
同样,这工作得很好,因为调用divide的人不期望它返回任何东西,也不对返回值做任何事情。
Ori的回答已经解释了没有必要返回,但这是一个很好的练习。请注意,promise构造函数是抛出安全的,因此它将忽略稍后在路径中传递的抛出异常,基本上你有不容易观察到的副作用。
注意,早期返回在回调中也很常见:
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构造函数是throw安全的,它将异常转换为拒绝,但正如其他人指出的那样——一个promise只解决一次。
从技术上讲,这里不需要它1——因为一个承诺可以被解决或拒绝,只有一次。第一个Promise结果获胜,随后的每个结果都被忽略。这与node风格的回调不同。
也就是说,在实际情况下,确保只调用一个是很好的干净实践,在这种情况下确实如此,因为没有进一步的异步/延迟处理。“提前返回”的决定与在函数工作完成时终止函数与继续不相关或不必要的处理没有什么不同。
在适当的时间返回(或以其他方式使用条件来避免执行“其他”情况)减少意外地在无效状态下运行代码或执行不必要的副作用的机会;因此,它使代码更不容易“意外中断”。
1这个技术上的答案还取决于这样一个事实:在这种情况下,“return”后面的代码即使被省略,也不会导致副作用。JavaScript将愉快地除以0并返回+∞/-∞或NaN。