Обещания Bluebird на Node.js: обработка ошибок и исключений

Я использую обещания bluebird для приложения node.js (среда MEAN). Однако у меня возникают проблемы с пониманием обработки исключений/ошибок. Рассмотрим следующий код:

var Promise = require('bluebird'),
    library1 = Promise.promisifyAll(require('firstlibrary')),
    library2 = Promise.promisifyAll(require('secondlibrary'));

//main
exports.urlchecker = function(req, res) {
    library1.doSomething(req.body.url) //--> how to reject this promise?
        .then(function(response) {
            if (response == false) {
                throw new LinkError("URL invalid!");
            }

            library2.Foo(req.body.url)
                .then(function(response2) {
                    if (response2 == false) {
                        throw new SizeError("URL too long!");
                    }
                    res.json({
                        status: true
                    });
                }).catch(LinkError, function(e) { //--> causes error!
                    res.json({
                        status: false
                    });
                }).catch(SizeError, function(e) { //--> causes error!
                    res.json({
                        status: false
                    });
                }).catch(function(e) { //--> catch all other exceptions!
                    res.json({
                        status: false
                    });
                });
        });
};

library1 - обещал:

exports.doSomething = function(url, cb) {
    if (whatever == 0) {
        cb(null, false); //--> what to return to reject promise?
    } else {
        cb(null, true);
    }
};

У меня сейчас два вопроса.

  1. Что я должен вернуть от library1, чтобы его обещание было отклонено? Если не путем возврата значения, как я могу это сделать?
  2. Как определить и перехватить собственные исключения? Приведенный выше код приводит к этой ошибке:

    Unhandled rejection ReferenceError: LinkError/SizeError is not defined
    

person Igor P.    schedule 15.06.2015    source источник
comment
В зависимости от ответа библиотеки1 я хотел бы немедленно разрезать цепочку промисов (->библиотека2 тогда не будет вызываться) и ответить клиенту об ошибке.   -  person Igor P.    schedule 15.06.2015


Ответы (1)


.promisify*() превращает обычное соглашение обратного вызова Node.js в промисы. Частью этого соглашения является то, что ошибки передаются в качестве первого аргумента функции обратного вызова.

Другими словами, чтобы отклонить обещание, используйте cb(new Error(...)).

Пример:

var Promise = require('bluebird');

var library1 = {
  // If `doFail` is true, "return" an error.
  doSomething : function(doFail, cb) {
    if (doFail) {
      return cb(new Error('I failed'));
    } else {
      return cb(null, 'hello world');
    }
  }
};

var doSomething = Promise.promisify(library1.doSomething);

// Call that resolves.
doSomething(false).then(function(result) {
  console.log('result:', result);
}).catch(function(err) {
  console.log('error:', err);
});

// Call that rejects.
doSomething(true).then(function(result) {
  console.log('result:', result);
}).catch(function(err) {
  console.log('error:', err);
});

Что касается отсутствующих типов ошибок: я предполагаю, что они экспортируются secondlibrary, поэтому используйте library2.LinkError вместо LinkError. Если они не экспортируются, вы не можете их перехватить явно.

person robertklep    schedule 15.06.2015
comment
Это правильный способ сделать это - на самом деле он не имеет ничего общего с промисами, это просто то, как вы работаете с errbacks узла. Возможно, вы захотите ответить и на второй вопрос (ошибка подкласса). - person Benjamin Gruenbaum; 15.06.2015