在Bluebird的承诺链中将同步函数转换为异步的原因是什么?

时间:2016-03-05 05:13:32

标签: bluebird

Bluebird的文档和外部帖子提到了异步错误和同步错误之间的差异,并且有一些函数可以帮助将所有这些错误归结为异步错误(例如Promise.tryPromise.method)?这似乎是因为(除其他事项外)错误处理对于两者来说是不同的(同步是用try / catch捕获的,而async是用.catch捕获的。

但不要then语句接受同步功能(throws被视为拒绝,return视为已解决)或承诺(使用标准reject / { {1}})在一系列链式函数的第一个方法之后的任何一个? (例如,在a()。然后(b).then(c).catch(function(e){}) - b / c部分)。最终resolve似乎从promise中的拒绝或同步代码中的throw中收集错误。

这些额外的Bluebird函数的主要目的仅在于回调链的第一部分吗?或者是否有其他原因将同步代码转换为承诺。

1 个答案:

答案 0 :(得分:0)

让我们看一个非常基本的例子,我们在某段代码中有异步和同步路径:

var expiryTime = 1457155658238;
var cachedCopy = 'abcdefghijk';

var p = Date.now() > expiryDate ? getNewCopy() : cachedCopy;

p.then(function (information) {
  // do something
});

请注意这里的问题?由于cachedCopy不是承诺,如果条件沿着此路径行进,则会抛出错误。因此,我们需要将cachedCopy包装成一个承诺:

var p = Date.now() > expiryDate ? getNewCopy() : Promise.resolve(cachedCopy);

但是,如果我们必须为多个代码路径执行此操作,这可能会变得乏味。您可能想知道为什么我们不要简单地将它放入函数中,然后在返回值上调用Promise.resolve以将其包装到promise中。拿这个代码:

var expiryTime = 1457155658238;
var cachedCopy = 'abcdefghijk';
var canGetNewCopy = false;

function getInfo() {
  if (Date.now() < expiryDate) return cachedCopy;
  if (canGetNewCopy) return getNewCopy();
  throw new Error('fail!');
}

Promise.resolve(getInfo()).then(function (information) {
  // do something
}).catch(function (error) {
  console.log('an error occured!');
  cleanup();
});

如果超过到期日会怎样?因为getInfo()会抛出错误,所以清理代码不会运行。

Bluebird的Promise.try解决了所有这些问题。通过捕获传递的函数内部抛出的错误,以及在同步返回的情况下将值包装到promise中,这可以节省大量代码包装并减少代码中细微错误的可能性。现在我们的示例看起来像这样:

var expiryTime = 1457155658238;
var cachedCopy = 'abcdefghijk';
var canGetNewCopy = false;

Promise.try(function () {
  if (Date.now() < expiryDate) return cachedCopy;
  if (canGetNewCopy) return getNewCopy();
  throw new Error('fail!');
}).then(function (information) {
  // do something
}).catch(function (error) {
  console.log('an error occured!');
  cleanup();
});

现在如果在Promise.try回调中抛出错误,则返回的promise将被拒绝,因此清理代码将运行。出于类似的原因,Bluebird中也存在Promise.method(以确保API中的函数始终返回承诺)。