阻止Bluebird承诺中的错误传播

时间:2015-02-28 21:58:07

标签: javascript promise bluebird

如何阻止抛出的错误一直传播到链中?它显示在我的catch()块中,但它不会因未捕获的异常而停止并崩溃服务器。

我将此作为节点cron作业(node-cron)的一部分运行为:

var cronJob = require('cron').CronJob;
var cron = require('../lib/cron')

var c = new cronJob('* * * * * *', function() {
  console.log('Cron starting');
  mycode.run();
}, function() {
  console.log('Cron executed');
}, true);
 c.start();

在我的cron.js

  module.exports = {
    run: function() {
      return job.getAndStore().catch(function(e) {
        // This prints but it keeps on going so to speak - it doesn't 'catch', just notifies me
        console.log('ERROR', e); 
      });
    }
  };

控制台转储:

Cron starting
ERROR [TypeError: undefined is not a function]
Cron starting
Uncaught Exception
[TypeError: undefined is not a function]
TypeError: undefined is not a function

我必须这样做,我知道不太正确:

try {
  run();
} catch(e) { 
  console.log('Now it stops')
}

run()是某些cron库的一部分,它没有任何promise支持,所以我将它包装在函数中以调用它。

编辑由于我认为我的问题与后续调用有关,我认为这与我如何处理2+以上的Mongo连接有关:

    //  Create a Mongo connection
Job.prototype.getDb = function(id) {
  var self = this;
  return new P(function(resolve, reject) {
    if (!self.db) {
      return Mongo.connectAsync(self.options.connection)
      .then(function(c) {
        self.db = c;
        debug('Got new connection');
        resolve(c);
      });
    }
    debug('Got existing connection');
    resolve(self.db);
  });
};

// Fetch stuff
Job.prototype.getAndStore = function(c) {
  return this.getDb().then(function() {
    throw new Error('Boom');
  });
};

2 个答案:

答案 0 :(得分:1)

您的catch回调仅在第一次执行时才会执行。您在第二次运行cron作业时遇到未捕获的异常,看起来job.getAndStore()不会返回被拒绝的承诺,但throw同步。它不应该,should always return a promise

您可以使用Bluebirds Promise.try自动捕获此类异常并将其转换为承诺拒绝。或者您将getAndStore函数打包在Promise.method

var safeGetAndStore = Promise.method(job.getAndStore.bind(job));

module.exports = {
  run: function() {
    return safeGetAndStore().catch(function(e) {
      console.log('ERROR', e); 
    });
  }
};

在您的具体情况下,问题是您的job确实缓存了db连接并在它已经可用时返回 - 但您需要使用.then返回一个承诺方法。您应该简单地缓存承诺本身:

Job.prototype.getDb = function(id) {
  if (!this.db) {
    this.db = Mongo.connectAsync(self.options.connection);
  return this.db;
};

答案 1 :(得分:0)

使用done,至少如果蓝鸟正确实现它,它将按预期工作。

catch(..)只是then(null, ..)的别名,它是承诺变换器,可以为进一步处理创建另一个承诺。

所以下面应该对你有用:

  module.exports = {
    run: function() {
      return job.getAndStore().done(null, function(e) {
        // This prints but it keeps on going so to speak - it doesn't 'catch', just notifies me
        console.log('ERROR', e); 
      });
    }
  };