我需要在 resolve/reject 之后 return 吗?
Do I need to return after early resolve/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
之后立即退出的习惯?
return
目的是在rejection后终止函数的执行,阻止其后代码的执行。
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);
执行,这并不是严格需要的。但是,最好还是终止执行以防止将来可能出现的陷阱。此外,最好避免不必要地使用 运行 代码。
背景
承诺可以处于以下 3 种状态之一:
- pending - 初始状态。我们可以从 pending 转到其他状态之一
- 已完成 - 操作成功
- 已拒绝 - 操作失败
当一个承诺被履行或拒绝时,它将无限期地保持在这个状态(已解决)。因此,拒绝已履行的承诺或履行已拒绝的承诺将无效。
此示例片段显示,虽然承诺在被拒绝后得到履行,但它仍然被拒绝。
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));
那么为什么我们需要return?
虽然我们无法更改已解决的承诺状态,但拒绝或解决不会停止其余功能的执行。该函数可能包含会产生混乱结果的代码。例如:
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));
即使该函数现在不包含此类代码,这也可能会造成未来的陷阱。未来的重构可能会忽略这样一个事实,即代码在 promise 被拒绝后仍在执行,并且很难调试。
在resolve/reject之后停止执行:
这是标准的 JS 控制流内容。
- Return后
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 和
resolve
/ reject
- 由于回调的 return 值被忽略,我们可以通过 returning 保存一行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
选项之一,因为代码更简洁。
技术上这里不需要1 - 因为 Promise 可以被解决 或被拒绝了,排他性地而且只有一次。第一个 Promise 结果获胜,随后的每个结果都将被忽略。这与 Node 风格的回调不同。
话虽这么说,良好的清洁做法 确保在可行的情况下准确调用一个,在这种情况下确实如此,因为没有进一步的 async/deferred 处理. 决定 "return early" 与在其工作完成后结束任何功能没有什么不同 - 与继续不相关或不必要的处理。
在适当的时间返回(或使用条件判断来避免执行 "other" 情况)减少意外 运行 代码处于无效状态或执行不需要的副作用的可能性;因此,它使代码不太容易出现 'breaking unexpectedly'.
1 这个 技术上 答案还取决于 在这种情况下 代码在 "return" 之后,如果将其省略,不会产生副作用。 JavaScript 将 愉快地 除以零和 return +Infinity/-Infinity 或 NaN。
Ori 的回答已经解释了没有必要 return
但这是一个很好的做法。请注意,promise 构造函数是安全抛出的,因此它会忽略稍后在路径中传递的抛出异常,本质上,您有无法轻易观察到的副作用。
请注意,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.
}
因此,虽然在 promise 中这是一个很好的做法,但需要 回调。关于您的代码的一些注意事项:
- 您的用例是假设的,不要实际使用同步操作的承诺。
- promise 构造函数 忽略 return 值。如果您 return 一个非未定义的值,一些库会警告您不要在那里 returning 的错误。大多数都没有那么聪明。
- promise 构造函数是安全的,它将异常转换为拒绝,但正如其他人指出的那样 - promise 解析一次。
一个常见的习惯用法(可能适合也可能不适合)是将 return
与 reject
结合起来,同时拒绝承诺并退出函数,这样包括 resolve
在内的函数的其余部分不会被执行。如果你喜欢这种风格,它可以让你的代码更紧凑一些。
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) return reject("Cannot divide by 0");
^^^^^^^^^^^^^^
resolve(numerator / denominator);
});
}
这很好用,因为 Promise 构造函数不对任何 return 值做任何事情,并且在任何情况下 resolve
和 reject
return 什么都不做。
同样的习语可以与另一个答案中显示的回调样式一起使用:
function divide(nom, denom, cb){
if(denom === 0) return cb(Error("Cannot divide by zero"));
^^^^^^^^^
cb(null, nom / denom);
}
同样,这工作正常,因为调用 divide
的人不希望它 return 任何东西,也不对 return 值做任何事情。
如果您在 resolve/reject 之后不 "return",则可能会在您打算停止后发生坏事(例如页面重定向)。资料来源:我运行进入这个。
在许多情况下,可以单独并立即验证参数 return 被拒绝的承诺 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));
假设我有以下代码。
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if(denominator === 0){
reject("Cannot divide by 0");
return; //superfluous?
}
resolve(numerator / denominator);
});
}
如果我的目标是使用reject
提前退出,我是否也应该养成return
之后立即退出的习惯?
return
目的是在rejection后终止函数的执行,阻止其后代码的执行。
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);
执行,这并不是严格需要的。但是,最好还是终止执行以防止将来可能出现的陷阱。此外,最好避免不必要地使用 运行 代码。
背景
承诺可以处于以下 3 种状态之一:
- pending - 初始状态。我们可以从 pending 转到其他状态之一
- 已完成 - 操作成功
- 已拒绝 - 操作失败
当一个承诺被履行或拒绝时,它将无限期地保持在这个状态(已解决)。因此,拒绝已履行的承诺或履行已拒绝的承诺将无效。
此示例片段显示,虽然承诺在被拒绝后得到履行,但它仍然被拒绝。
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));
那么为什么我们需要return?
虽然我们无法更改已解决的承诺状态,但拒绝或解决不会停止其余功能的执行。该函数可能包含会产生混乱结果的代码。例如:
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));
即使该函数现在不包含此类代码,这也可能会造成未来的陷阱。未来的重构可能会忽略这样一个事实,即代码在 promise 被拒绝后仍在执行,并且很难调试。
在resolve/reject之后停止执行:
这是标准的 JS 控制流内容。
- Return后
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 和
resolve
/reject
- 由于回调的 return 值被忽略,我们可以通过 returning 保存一行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
选项之一,因为代码更简洁。
技术上这里不需要1 - 因为 Promise 可以被解决 或被拒绝了,排他性地而且只有一次。第一个 Promise 结果获胜,随后的每个结果都将被忽略。这与 Node 风格的回调不同。
话虽这么说,良好的清洁做法 确保在可行的情况下准确调用一个,在这种情况下确实如此,因为没有进一步的 async/deferred 处理. 决定 "return early" 与在其工作完成后结束任何功能没有什么不同 - 与继续不相关或不必要的处理。
在适当的时间返回(或使用条件判断来避免执行 "other" 情况)减少意外 运行 代码处于无效状态或执行不需要的副作用的可能性;因此,它使代码不太容易出现 'breaking unexpectedly'.
1 这个 技术上 答案还取决于 在这种情况下 代码在 "return" 之后,如果将其省略,不会产生副作用。 JavaScript 将 愉快地 除以零和 return +Infinity/-Infinity 或 NaN。
Ori 的回答已经解释了没有必要 return
但这是一个很好的做法。请注意,promise 构造函数是安全抛出的,因此它会忽略稍后在路径中传递的抛出异常,本质上,您有无法轻易观察到的副作用。
请注意,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.
}
因此,虽然在 promise 中这是一个很好的做法,但需要 回调。关于您的代码的一些注意事项:
- 您的用例是假设的,不要实际使用同步操作的承诺。
- promise 构造函数 忽略 return 值。如果您 return 一个非未定义的值,一些库会警告您不要在那里 returning 的错误。大多数都没有那么聪明。
- promise 构造函数是安全的,它将异常转换为拒绝,但正如其他人指出的那样 - promise 解析一次。
一个常见的习惯用法(可能适合也可能不适合)是将 return
与 reject
结合起来,同时拒绝承诺并退出函数,这样包括 resolve
在内的函数的其余部分不会被执行。如果你喜欢这种风格,它可以让你的代码更紧凑一些。
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) return reject("Cannot divide by 0");
^^^^^^^^^^^^^^
resolve(numerator / denominator);
});
}
这很好用,因为 Promise 构造函数不对任何 return 值做任何事情,并且在任何情况下 resolve
和 reject
return 什么都不做。
同样的习语可以与另一个答案中显示的回调样式一起使用:
function divide(nom, denom, cb){
if(denom === 0) return cb(Error("Cannot divide by zero"));
^^^^^^^^^
cb(null, nom / denom);
}
同样,这工作正常,因为调用 divide
的人不希望它 return 任何东西,也不对 return 值做任何事情。
如果您在 resolve/reject 之后不 "return",则可能会在您打算停止后发生坏事(例如页面重定向)。资料来源:我运行进入这个。
在许多情况下,可以单独并立即验证参数 return 被拒绝的承诺 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));