【问题标题】:should i use `return` in Promise?我应该在 Promise 中使用“return”吗?
【发布时间】:2016-04-12 15:41:26
【问题描述】:
function saveToTheDb(value) {  
  return new Promise(function(resolve, reject) {
    db.values.insert(value, function(err, user) { // remember error first ;)
      if (err) {
        return reject(err); // don't forget to return here
      }
      resolve(user);
    })
  }
}

这是我从here 看到的代码。 我对 return 关键字感到困惑。

对于resolve(user);,我需要return吗?

对于reject(user);,我需要return吗?

【问题讨论】:

  • 不,你不需要返回,你只需要调用回调解析/拒绝函数。
  • 它有return reject(err) 来停止该功能。替代方案是if (err) { reject(err); } else { resolve(user); }
  • @Phil - 虽然在这个例子中它并不重要,因为 Promise 只能被履行/拒绝一次,所以如果拒绝被调用,resolve 将被有效地忽略
  • @Phil 你能详细解释一下吗?对于其他回调,必须使用retrun
  • 看在上帝的份上 - 不要手动编写此代码 - 您可以使用一个库(如 bluebird),它会一次性为您生成回调 API 的包装器。

标签: node.js promise


【解决方案1】:

正如@JaromandaX 所说,在这种情况下,return 语句没有任何区别。 来自docs

在所有解决承诺的情况下(即履行或拒绝),解决方案是永久性的,无法重置。如果 promise 已经解决,尝试调用 resolve、reject 或 notify 将是无操作的。

【讨论】:

  • 不正确 - 一旦承诺被拒绝/履行,任何进一步的尝试都会被忽略
  • @JaromandaX 我用你的解释编辑了我的答案,谢谢。
  • 说“没有任何区别”并不是 100% 正确的。它不会对程序的行为产生任何影响,但省略它会导致对resolve 的不必要调用,这可能会产生一些较小的性能影响,并且可能不太重要的是,它会使程序在语义上读起来稍微少一些,因为它似乎它可能正在解决承诺,尽管出于您实际上提到的原因,它当然不是。
  • 这也让程序更容易出错,因为当一些开发者无意中在resolve之前添加了另一个语句,想象它只会在成功的情况下执行,实际上它甚至在reject。因此,我会说绝对推荐return
【解决方案2】:

没有必要在new Promise() 回调中使用return 语句。 Promise 构造函数不期望回调有任何类型的返回值。

因此,在该回调中使用 return 语句的原因只是为了控制该函数中的执行流程。如果您希望回调中的执行完成并且不再执行该回调中的代码,您可以在那时发出return;

例如,您可以在没有return 语句的情况下编写这样的代码:

function saveToTheDb(value) {  
  return new Promise(function(resolve, reject) {
    db.values.insert(value, function(err, user) { 
      if (err) {
        reject(err);
      } else {
        resolve(user);
      }
    });
  }
}

在这种情况下,您使用 if/else 子句来确保函数中的控制流采用正确的路径,并且不需要或使用 return


在承诺像这样的异步函数时,一个常见的快捷方式是:

function saveToTheDb(value) {  
  return new Promise(function(resolve, reject) {
    db.values.insert(value, function(err, user) { 
      if (err) return reject(err);
      resolve(user);
    });
  }
}

这与前面的代码块在功能上没有什么不同,但它的类型更少,更紧凑。 return 前面的 return 语句仅出于控制流原因,以防止在出现错误时执行 resolve(user); 语句,因为所需的控制流是调用 reject(err) 然后不执行任何其他操作回调。


事实上,在这种特定情况下,实际上甚至不需要最后一个块中的return 语句,因为在reject() 之后执行resolve() 不会做任何事情,因为承诺被锁定到首先发生的解决或拒绝.但是,执行不必要的代码通常被认为是不好的做法,因此许多人认为最好使用控制结构流(例如 if/elsereturn 来仅执行需要的代码。

因此,这在技术上也可行,但不被认为是最佳做法,因为它执行不必要的代码并且结构不清晰:

function saveToTheDb(value) {  
  return new Promise(function(resolve, reject) {
    db.values.insert(value, function(err, user) {
      if (err) reject(err);
      resolve(user);
    });
  }
}

仅供参考,您在这里所做的称为“promisifying”,它使与回调一起工作的常规异步函数变为返回承诺的函数。有一些库和函数可以在一个函数调用中为您“承诺”一个函数或整个函数对象(例如整个 API),因此您不必手动执行此操作。例如,我经常使用 Bluebird,它提供Promise.promisify() 来承诺单个函数或Promise.promisifyAll(),它将承诺对象或原型上的所有方法。这非常有用。例如,您可以通过以下方式获得整个 fs 模块的承诺版本:

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));

然后,您可以使用返回承诺的方法,例如:

fs.readFileAsync("file.txt").then(function(data) {
    // do something with file.txt data here
});

【讨论】:

  • 短暂返回意味着将终止代码执行。
  • @FarisRayhan - 是的,这就是我回答的第二段所说的。 return 用于控制代码流(退出回调)。
  • 有时甚至只是:new Promise((resolve, reject) => db.values.insert(value, (err, user) => err ? reject(err) : resolve(user)) );
【解决方案3】:

一般来说,在 NodeJS 中,你不应该过多地使用 Promise 构造函数。

promise 构造函数用于converting APIs that don't return promises to promises。您应该考虑使用提供 promisification 的库(即使您全面使用原生 Promise),因为它提供了一个安全的替代方案,在错误处理逻辑中没有细微的错误。

自动承诺也相当快。

也就是说,您的问题的答案是“是”。

这样做是非常安全的,promise 构造函数没有什么特别之处——它们只是普通的 JavaScript。 Domenic 讨论了 Promise 构造函数 in his blog 的设计。

提前返回是完全安全的(就像任何其他函数一样) - 它实际上在常规异步函数中很常见。

(另外,在您的示例代码中,您应该只使用Promise.resolve,但我认为它很简单只是因为它是一个示例)。

从副本中复制了这个答案

【讨论】:

  • 您能否提供一个简单的示例来说明国产承诺中的“带有错误处理逻辑的细微错误”?
  • @torazaburo 当然,您需要处理您同步调用throws 的函数的情况,例如使用多个参数调用回调并处理代理同步抛出的情况你在异步上下文中调用resolve。很有趣。
猜你喜欢
  • 2016-09-12
  • 2017-07-15
  • 2018-09-05
  • 2017-05-16
  • 2019-08-18
  • 2016-10-03
  • 2014-09-20
  • 2019-09-29
  • 1970-01-01
相关资源
最近更新 更多