【问题标题】:Promise is fulfilled on error错误实现承诺
【发布时间】:2018-03-15 18:50:48
【问题描述】:

好吧,我以为我已经理解了 Promise,但似乎我在这方面遗漏了一些东西......

var redisPromise = new Promise(function(resolve, reject) {
  redisClient.on('error', reject);
  redisClient.on('ready', resolve);
}).then(function() {
  // THIS ISN'T CALLED - CORRECT
  log.enabled && log('connected, version: %s', redisClient.server_info.redis_version);
  return redisClient;
}).catch(function() {
  // THIS GETS CALLED - CORRECT
  log('failed connecting to database:', e.message);
});

redisPromise.then(function() {
  log("This shouldn't be called when connection fails");
});

对于 Redis 连接失败的情况,我希望返回的 Promise 被拒绝。但是由于某种原因,它已经实现了。我在这里遗漏了什么吗?

我正在使用Bluebird 实现。那里可能有一些错误吗?我有点怀疑,这一切似乎都有很好的记录并且有意义......在纸上。

已解决

https://github.com/petkaantonov/bluebird/issues/156进行全面讨论

【问题讨论】:

  • 我很好奇,如果程序连接数据库失败,你想让程序做什么?出口?向用户发送错误页面?尝试重新连接?或者您真的希望它只记录错误并闲逛?

标签: javascript error-handling promise bluebird


【解决方案1】:

复制 GH 问题的答案,包括 Domenic 的代码示例:

Domenic 给出了以下示例:想想等效的同步代码:

try {
   ...
} catch (e) {
  // THIS GETS CALLED - CORRECT
  log('failed connecting to database:', e.message);
}

log('This shouldn't be called when connection fails :/');

你会明白为什么你的期望没有那么好。

添加到 Domenic 的出色模拟中。 如果你想发出执行失败的信号并处理它,你需要重新抛出:

try {
   ...
} catch (e) {
  // THIS GETS CALLED - CORRECT
  log('failed connecting to database:', e.message);
  throw e;
}

在你的情况下:

}).catch(function(e) {
  log('failed connecting to database:', e.message);
  throw e;
});

如果您想发出异常类型的信号 - 抛出您自己的失败类型。可能未处理的拒绝的类比是当您输入同步代码并且不处理它时会发生什么。它默认将其记录到控制台。

这是一个我不太喜欢的替代解决方案:

var redisPromise = new Promise(function(resolve, reject) {
  redisClient.on('error', reject);
  redisClient.on('ready', resolve);
}).then(function() {
  log.enabled && log('connected, version: %s', redisClient.server_info.redis_version);
  return redisClient;
});
redisPromise.catch(function() { 
  log('failed connecting to database:', e.message);
});

redisPromise.then(function() { 
  log('This shouldn't be called when connection fails :/');
});

【讨论】:

  • 感谢您在此处粘贴。
  • 当然,请随时提出更多问题,它会创建一个很好的知识库:)
【解决方案2】:

then 在一些库中创建了一个新的承诺。我的猜测是,bluebird 也会用catch 创建一个承诺。你链接它们的方式,redisPromise 指的是“catch”承诺,而不是第一个承诺。而“catch”确实解决了。

如果我是对的,这应该可以按预期工作:

var redisPromise = new Promise(function(resolve, reject) {
  redisClient.on('error', reject);
  redisClient.on('ready', resolve);
});

redisPromise.then(function() {
  // THIS ISN'T CALLED - CORRECT
  log.enabled && log('connected, version: %s', redisClient.server_info.redis_version);
  return redisClient;
}).catch(function() {
  // THIS GETS CALLED - CORRECT
  log('failed connecting to database:', e.message);
});

redisPromise.then(function() {
  log("This shouldn't be called when connection fails");
});

【讨论】:

  • 是的,catch 应该是then(null, handler) 的别名。但我认为你有道理。我必须多摆弄它,因为像这样使用它,Bluebird 会将该错误传播到顶层并输出到控制台。我不喜欢这种行为。
【解决方案3】:

这不是你想要的简单

new Promise(function(resolve, reject) {
  redisClient.on('error', reject);
  redisClient.on('ready', resolve);
}).then(function() {
  // THIS ISN'T CALLED - CORRECT
  log.enabled && log('connected, version: %s', redisClient.server_info.redis_version);
  return redisClient;
}).then(function() {
  log("This shouldn't be called when connection fails");
}).catch(function() {
  // THIS GETS CALLED - CORRECT
  log('failed connecting to database:', e.message);
});

等同于:

try {
   var redisClient = ...
   log.enabled && log('connected, version: %s', redisClient.server_info.redis_version);
   log("This shouldn't be called when connection fails");
} 
catch(e) {
   log('failed connecting to database:', e.message);
}

【讨论】:

  • 是的,它让我很难将其视为同步代码,但希望我会习惯它。在 GH 的discussion 之后,现在对我来说很有意义。
猜你喜欢
  • 2020-09-20
  • 1970-01-01
  • 2014-12-29
  • 2018-10-22
  • 1970-01-01
  • 2013-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多