Цепочка обещаний с неудачей

Глядя на обработку промисов в этом блоге, я изменил пример отказа:

var myApp = angular.module('myApp',[]);

myApp.controller("MyCtrl", function ($q, $scope) {

    (function() {
        var deferred = $q.defer();
        var promise = deferred.promise;
        promise.then(function(result) {
            console.log("success pass 1 - " + result);
            return result;
        }, function(reason) {
            console.log("failure pass 1, reason:", reason);
            throw new Error("failed with: " + reason);
        }).
        then(function(result) {
            console.log("2nd success! result: ", result);
        }, function(reason) {
            console.log("2nd failure! reason: ", reason);
        });


        console.log("calling deferred.reject('bad luck')");
        deferred.reject("bad luck");

    })();

Для моей первой функции отказа я заметил, что замена throw на return приведет к:

calling deferred.reject('bad luck') 
failure pass 1, reason: bad luck 
2nd success! result:  Error {stack: (...), message: "failed with: bad luck"}

В итоге я заменил return на throw для достижения нужного failure -> failure результата.

calling deferred.reject('bad luck') 
failure pass 1, reason: bad luck 
Error: failed with: bad luck at ...app.js
2nd failure! reason: Error {stack: ... "failed with: bad luck"}

Выброшенная ошибка, похоже, не была обнаружена. Почему это? Разве внутренний сбой не должен был поймать эту выброшенную ошибку?

Кроме того, в связанном промисе может ли быть достигнут случай последовательной ошибки (в данном случае случай сбоя 2-го цепочного промиса) только через бросок Error?


person Kevin Meredith    schedule 31.05.2014    source источник


Ответы (2)


Это выбор дизайна $q, который в некотором смысле очень неортодоксален.

В $q было принято дизайнерское решение о том, что throw и reject обрабатываются по-разному, поскольку библиотека не отслеживает необработанные отказы. Это сделано для того, чтобы избежать случая, когда ошибки проглатываются:

JSNO.parse("{}"); // note the typo in JSON, in $q, since this is an error
                  // it always gets logged, even if you forgot a `.catch`.
                  // in Q this will get silently ignored unless you put a .done
                  // or a `catch` , bluebird will correctly track unhandled
                  // rejections for you so it's the best in both.

Их ловят, обрабатывают, но все равно регистрируют.

В $q вместо этого используются отказы:

return $q.reject(new Error("failed with: " + reason));
person Benjamin Gruenbaum    schedule 31.05.2014
comment
Не будет $q.reject(...), верно? Разве это не было бы что-то вроде deferred.reject(...), где deferred = $q.defer()? - person Marc Kline; 31.05.2014
comment
Нет, отсрочки нужны только при создании нового промиса. Я определенно имел в виду $q.reject здесь - person Benjamin Gruenbaum; 31.05.2014
comment
Ах. Я думал, что отклонение и разрешение доступны только для того, что было возвращено из отсрочки. Мне любопытен вариант использования для вызова его на $ q. Может быть, я поиграю и напишу вопрос, если это необходимо. - person Marc Kline; 01.06.2014

вы, возможно, уже нашли. Если вы хотите связать промисы с ошибкой, укажите обработчик ошибки только в конце цепочки.

    promise.then(function(result) {
        console.log("success pass 1 - " + result);
        return result;
    } /* don't handle failure here. Otherwise, a
         new promise (created by 'then') wraps the
         return value (normally undefined) in a new
         promise, and it immediately solves it 
         (means success) since the return value of
         your failure handler is not a promise.

         leave failure handler empty, 'then' will pass
         the original promise to next stage if the
         original promise fails. */
    ).
    then(function(result) {
        console.log("2nd success! result: ", result);
    }, function(reason) {

        /* both 1st and 2nd failure can be captured here */

        console.log("1st or 2nd failure! reason: ", reason);
    });
person huocp    schedule 29.09.2015