Angular 1.6.0: возможно необработанная ошибка отклонения

У нас есть шаблон для разрешения промисов в нашем приложении Angular, который хорошо служил нам до Angular 1.6.0:

    resource.get().$promise
        .then(function (response) {
        // do something with the response
        }, function (error) {
            // pass the error the the error service
            return errorService.handleError(error);
        });

И вот как мы вызываем ошибку в Карме:

    resourceMock.get = function () {
        var deferred = $q.defer();
        deferred.reject(error);
        return { $promise: deferred.promise };
    };

Теперь, с обновлением до 1.6.0, Angular внезапно жалуется в наших модульных тестах (в Karma) на отклоненные промисы с ошибкой «Возможно, необработанное отклонение». Но мы обрабатываем отклонение во второй функции, которая вызывает нашу службу ошибок.

Что именно здесь ищет Angular? Как он хочет, чтобы мы «справились» с отказом?


person Groucho    schedule 09.12.2016    source источник
comment
Я заметил это и в нашей кодовой базе. Как ни странно, запуск пакета с хромированной пусковой установкой работает нормально. PhantomJS жалуется.   -  person Mario Tacke    schedule 19.12.2016
comment
Если вы получили это, а не просто обновили, вот как вы можете проверить свою версию Angular: stackoverflow.com/questions/16017699/   -  person hubatish    schedule 08.05.2017
comment
Принятый ответ рекомендует скрыть ошибку. Дубликат предлагает более надежную альтернативу с этим ответом.   -  person georgeawg    schedule 14.08.2018


Ответы (11)


Попробуйте добавить этот код в свой конфиг. Однажды у меня была похожая проблема, и этот обходной путь помог.

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);
person Cengkuru Michael    schedule 02.02.2017
comment
Я должен отметить, что это просто скрывает ошибку, по словам разработчиков, в коде есть некоторая проблема, и это просто маскирует ошибку. - person Sachin Sharma; 12.07.2017
comment
Согласитесь, хотя это может избежать проблемы, основная причина остается, и вместо этого разработчик должен обрабатывать случай ошибки. - person Skrew; 17.08.2017
comment
Какой конкретно файл конфигурации? - person Hobbamok; 27.09.2018

Код, который вы показываете, будет обрабатывать отклонение, которое происходит до вызова .then. В такой ситуации будет вызван второй обратный вызов, который вы передаете .then, и будет обработано отклонение.

Однако, когда обещание, на котором вы вызываете .then, успешно, оно вызывает 1-й обратный вызов. Если этот обратный вызов выдает исключение или возвращает отклоненное обещание, это полученное отклонение не будет обработано, поскольку второй обратный вызов не обрабатывает отклонение по причине первого. Именно так работают реализации промисов, совместимые со спецификацией Promises/A+, а промисы Angular совместимы.

Вы можете проиллюстрировать это с помощью следующего кода:

function handle(p) {
    p.then(
        () => {
            // This is never caught.
            throw new Error("bar");
        },
        (err) => {
            console.log("rejected with", err);
        });
}

handle(Promise.resolve(1));
// We do catch this rejection.
handle(Promise.reject(new Error("foo")));

Если вы запустите его в Node, который также соответствует Promises/A+, вы получите:

rejected with Error: foo
    at Object.<anonymous> (/tmp/t10/test.js:12:23)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3
(node:17426) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: bar
person Louis    schedule 09.12.2016
comment
Хорошие моменты! Да, цель состоит в том, чтобы обработать отклонение, которое происходит до вызова .then. Код, который вызывает это отклонение (и который работал для Angular 1.5.9), был добавлен к исходному вопросу. - person Groucho; 09.12.2016
comment
Как на самом деле исправить запрошенный код шаблона? - person vip; 13.12.2016
comment
Хорошо, исправление похоже на $promise.then(success).catch(error), где catch перехватывает все ошибки, подробнее в разделе «Примечания» по адресу миграция - person vip; 13.12.2016
comment
это действительно должен быть правильный ответ - person tcmoore; 13.02.2018
comment
Что, если ваша функция по замыслу возвращает отклоненное обещание? Подобно тому, как $http.get() возвращает обещание, которое по замыслу отклоняется, если запрос не выполнен. У меня есть функции, которые возвращают обещания, и в некоторых случаях они могут возвращать $q.reject(err), кажется, угловому это не нравится, если только я не стираю предупреждения? - person Ryan Silva; 29.03.2018

Первый вариант — просто скрыть ошибку, отключив ее, настроив errorOnUnhandledRejections в конфигурации $qProvider как предложено Cengkuru Michael

НО это только отключит ведение журнала. Сама ошибка останется

Лучшим решением в этом случае будет обработка отказа методом .catch(fn):

resource.get().$promise
    .then(function (response) {})
    .catch(function (err) {});

ССЫЛКИ:

person Andrii Verbytskyi    schedule 28.07.2017

Нашел проблему, откатившись на Angular 1.5.9 и повторно запустив тест. Это была простая проблема с инъекцией, но Angular 1.6.0 заменил ее, вместо этого выдав ошибку «Возможно необработанный отказ», скрывая фактическую ошибку.

person Groucho    schedule 12.12.2016
comment
В настоящее время для меня это большая проблема, поскольку я переношу кодовую базу и заменяю старую введенную зависимость. Вы нашли способ предотвратить это запутывание и заставить его выдавать настоящую ошибку? - person ChrisJ; 17.04.2017
comment
Верхний ответ выше исправит это в работающем коде, но я не смог заставить его выдать ошибку в Karma без отката к Angular 1.5.9. - person Groucho; 17.04.2017

Чтобы избежать необходимости вводить дополнительные .catch(function () {}) в свой код в нескольких местах, вы можете добавить decorator к $exceptionHandler.

Это более подробный вариант, чем другие, но вам нужно внести изменения только в одном месте.

angular
    .module('app')
    .config(configDecorators);

configDecorators.$inject = ["$provide"];
function configDecorators($provide) {

    $provide.decorator("$exceptionHandler", exceptionHandler);

    exceptionHandler.$inject = ['$delegate', '$injector'];
    function exceptionHandler($delegate, $injector) {
        return function (exception, cause) {

            if ((exception.toString().toLowerCase()).includes("Possibly unhandled rejection".toLowerCase())) {
                console.log(exception); /* optional to log the "Possibly unhandled rejection" */
                return;
            }
            $delegate(exception, cause);
        };
    }
};
person Urielzen    schedule 27.05.2018

Вы можете замаскировать проблему, отключив errorOnUnhandledRejections, но ошибка говорит, что вам нужно «обработать возможный отказ», поэтому вам просто нужно добавить улов к вашему обещанию.

resource.get().$promise
    .then(function (response) {
    // do something with the response
    }).catch(function (error)) {
        // pass the error to the error service
        return errorService.handleError(error);
    });

Ссылка: https://github.com/angular-ui/ui-router/issues/2889

person giselleghadyani    schedule 16.05.2017

Пожалуйста, проверьте ответ здесь:

Возможно, необработанный отказ в Angular 1.6

Это было исправлено с помощью 316f60f, и это исправление включено в выпуск v1.6.1.

person Piotr Pradzynski    schedule 23.12.2016
comment
Все еще получаю это в 1.6.2 - person Daniel Bonnell; 17.05.2017
comment
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. – Из обзора - person Mostafa Berg; 05.02.2018
comment
@MostafaTorbjørnBerg спасибо. Я обновил ответ. - person Piotr Pradzynski; 05.02.2018

Я наблюдал такое же поведение во время выполнения теста. Странно, что на продакшене код работает нормально, а сбоит только на тестах.

Простое решение, чтобы сделать ваши тесты счастливыми, — это добавить catch(angular.noop) к макету обещания. В случае приведенного выше примера это должно выглядеть так:

resourceMock.get = function () {
    var deferred = $q.defer();
    deferred.reject(error);
    return { $promise: deferred.promise.catch(angular.noop) };
};

person Valdermeyder Hussar    schedule 15.12.2016

Я также столкнулся с той же проблемой после обновления до Angular 1.6.7, но когда я просмотрел код, для моего случая была выдана ошибка $interval.cancel(interval);.

Моя проблема была решена после того, как я обновил angular-mocks до последней версии (1.7.0).

person Dilip    schedule 04.06.2018

У меня появилось такое же уведомление после внесения некоторых изменений. Это оказалось из-за того, что я изменил один запрос $http на несколько запросов с использованием службы angularjs $q.

Я не обернул их в массив. например

$q.all(request1, request2).then(...) 

скорее, чем

$q.all([request1, request2]).then(...)

Я надеюсь, что это может сэкономить кому-то время.

person JamesEddyEdwards    schedule 26.06.2018

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

В моем случае я использовал angular-i18n и асинхронно получал словарь локали. Проблема заключалась в том, что файл json, который он получал, имел неправильный отступ (смешение пробелов и вкладок). Запрос GET не завершился ошибкой.

Исправление отступа решило проблему.

person monstercode    schedule 29.01.2018