Ошибка обработки обещаний jQuery AJAX с помощью Q

Я использую jQuery для AJAX, но Q в другом месте нашего приложения, поэтому хочу убедиться, что реализация Promise непротиворечива.

Я обернул вызов jQuery AJAX с Q следующим образом:

Q($.ajax(url, {
  type: 'get'
}));

И это отлично работает для успешных ответов. Теперь я хочу добавить обработку ошибок, я хочу иметь глобальную обработку ошибок (поскольку у нас есть согласованный ответ об ошибке с нашего сервера), сделав API следующим образом:

var xhr = function (url) {
    return Q($.ajax(url, {
      type: 'get'
    }))
    .then(function (data) {
      return data;
    }, function (res) {
      //global error handling
    });
};

И я ожидаю использовать его так:

xhr('...').then(function () { console.log('success'); });

Проблема заключается в том, что когда глобальный обработчик ошибок запускает метод "success" для потребителя метода xhr, вызывается.

Как бы вы это предотвратили?

Готовый образец можно увидеть здесь — http://jsbin.com/gudifu/3/edit.


person Aaron Powell    schedule 13.03.2015    source источник
comment
возможный дубликат второго обещания .then() не завершается ошибкой   -  person Bergi    schedule 13.03.2015


Ответы (2)


Из-за нестандартных промисов jQuery вам приходится прыгать через обручи, чтобы передать ошибку промису с принуждением Q.

Во-первых, сигнатура ошибки jqXHR — (jqXHR, textStatus, errorThrown), и обычно вы хотите передать второй аргумент, textStatus.

Во-вторых, две реализации промисов сильно различаются в отношении обработки ошибок:

  • jQuery: передает состояние ошибки, если из обратного вызова ошибки .then() не возвращается новое, разрешенное обещание. .fail() гарантированно распространяет состояние ошибки независимо от того, что возвращается. Неперехваченный throw завершит поток событий.
  • Вопрос: помечает ошибку как "обработанную" (т.е. отправляет ее по пути успеха), если только обратный вызов ошибки .catch(), .fail() или .then() не возвращает ошибку или не выдает новую, и в этом случае обещание продолжает выполняться. путь ошибки.

Следовательно, вам необходимо:

  • привязать .then(null, errHandler) к вашему звонку jQuery.ajax(), чтобы сообщить textStatus
  • выдать ошибку из Q на основе ошибки jQuery
var xhr = function (url) {
    return Q($.ajax(url, {
      type: 'get'
    }).then(null, function(jqXHR, textStatus, errorThrown) {
        return textStatus;
    })).then(function (data) {
        return data;
    }, function (textStatus) {
      //global error handling
      throw new Error(textStatus);
    });
};

В качестве альтернативы вы можете выдать правильную ошибку из jQuery и просто повторно выдать ее из Q.

var xhr = function (url) {
    return Q($.ajax(url, {
      type: 'get'
    }).then(null, function(jqXHR, textStatus, errorThrown) {
        return new Error(textStatus);
    })).then(function (data) {
        return data;
    }, function (err) {
      //global error handling
      throw err;
    });
};

Чистый эффект двух растворов будет почти идентичен. Я думаю, что я прав, говоря, что они будут показывать другой номер строки ошибки, если ошибка была зарегистрирована - первая связана с Q, а вторая - с jQuery.

person Roamer-1888    schedule 13.03.2015

Ваша проблема в том, что глобальный обработчик ошибок обрабатывает ошибку. В цепочке обещаний ваше xhr(…) обещание будет просто выполнено с тем, что вернул обработчик ошибок. Это похоже на catch, когда исключение было обработано, нормальное выполнение возобновляется.

Поэтому вам нужно повторно выдать исключение из обработчика, чтобы полученное обещание также было отклонено:

var xhr = function (url) {
    return Q($.ajax(url, {
        type: 'get'
    }))
    .then(null, function (res) {
        //global error handling
        throw res;
    });
};
person Bergi    schedule 13.03.2015
comment
Похоже, вы возвращаете тот же результат в jsbin? Функция вызывается дважды? - person guest271314; 13.03.2015
comment
да. По-видимому, вызывается на console по адресу runner-* piece ? :1 fail runner-3.25.21.min.js:1 pass through fail ? Попробую в stacksnippets, jsfiddle - person guest271314; 13.03.2015
comment
@guest271314: Я понятия не имею, о чем ты говоришь. Версия OP регистрирует fail - pass through success, а моя регистрирует fail - pass through fail, как и ожидалось. - person Bergi; 13.03.2015
comment
Да, похоже, здесь неправильно истолковал вопрос. Прочитал, просмотрел кусок на ОП и ожидал только один ответ об ошибке был или должен быть желаемым возвращенным результатом, причина. Перечитайте свой ответ и обратите внимание на глобальный обработчик ошибок. - person guest271314; 13.03.2015