假设我有以下代码。
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if(denominator === 0){
reject("Cannot divide by 0");
return; //superfluous?
}
resolve(numerator / denominator);
});
}
如果我的目标是使用reject
提前退出,我是否应该立即养成return
之后的习惯?
答案 0 :(得分:261)
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);
执行,这不是严格需要的。但是,最好终止执行以防止将来出现可能的陷阱。此外,不必要地防止运行代码是一种很好的做法。
背景
承诺可以是以下三种状态之一:
当承诺得到履行或拒绝时,它将无限期地(定居)保持在这种状态。因此,拒绝履行承诺或履行被拒绝的承诺将不起作用。
此示例代码段显示虽然承诺在被拒绝后已履行,但仍未被拒绝。
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));

即使该功能现在不包含此类代码,也会产生未来可能的陷阱。未来的重构可能会忽略在承诺被拒绝后代码仍然执行的事实,并且很难调试。
解决/拒绝后停止执行:
这是标准的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));

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
选项,因为代码更平坦。
答案 1 :(得分:28)
一个常见的习语,可能是或不是你的一杯茶,是将symfony new myblog lts
cd /home/debian8/myblog
php app/console server:run -vvv
[2016-03-19 15:14:11] php.DEBUG: fsockopen(): unable to connect to 127.0.0.1:8000 (Connection refused) {"type":2,"file":"/home/debian8/myblog/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ServerCommand.php","line":59,"level":28928}
[OK] Server running on http://127.0.0.1:8000
// Quit the server with CONTROL-C.
RUN '/usr/bin/php5' '-S' '127.0.0.1:8000' '/home/debian8/myblog/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php'
ERR [Sat Mar 19 15:14:36 2016] 127.0.0.1:36496 [200]: /
ERR [Sat Mar 19 15:14:37 2016] 127.0.0.1:36497 [200]: /_wdt/cf9a53
ERR [Sat Mar 19 15:14:37 2016] 127.0.0.1:36498 [200]: /favicon.ico
ERR [Sat Mar 19 15:14:37 2016] 127.0.0.1:36499 [200]: /favicon.ico
ERR
与return
结合起来,同时拒绝承诺并从函数中退出,以便剩下的不执行包括reject
的功能。如果您喜欢这种风格,它可以使您的代码更紧凑。
resolve
这很好用,因为Promise构造函数不对任何返回值执行任何操作,并且在任何情况下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);
}
的人不会指望它返回任何内容,也不会对返回值做任何事情。
答案 2 :(得分:9)
技术上这里不需要 1 - 因为承诺可以解决或被拒绝,完全和只有一次。第一个Promise结果获胜,每个后续结果都被忽略。这与节点式回调不同。
据说这是良好的清洁实践,以确保在实际操作中确切地调用一个,并且实际上在这种情况下,因为没有进一步的异步/延迟处理。 “早退”的决定与其工作完成时结束任何功能 - 与继续无关或不必要的处理相比没有什么不同。
在适当的时间返回(或以其他方式使用条件来避免执行“其他”情况)减少了在无效状态下意外运行代码或执行不必要的副作用的机会;因此,它使代码不易出现“意外破坏”。
1 这个技术答案还取决于在这种情况下“返回”之后的代码,如果省略,不会产生副作用。 JavaScript将高兴地除以零并返回+ Infinity / -Infinity或NaN。
答案 3 :(得分:7)
Ori的答案已经解释说return
没有必要,但这是一个好习惯。请注意,promise构造函数是throw安全的,因此它将忽略稍后在路径中传递的抛出异常,基本上你有副作用,你不能轻易观察。
请注意,早期return
在回调中也很常见:
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.
}
所以,尽管在promises中这是一个很好的做法,但需要带有回调。关于您的代码的一些注意事项:
答案 4 :(得分:7)
如果您在解决/拒绝后没有“返回”,那么在您意图停止之后,可能会发生错误的事情(例如页面重定向)。资料来源:我碰到了这个。
答案 5 :(得分:2)
在许多情况下,可以分别验证参数并立即使用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));