Угловой 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-это внезапно жалуемся в наших модульных тестах (в карме) на отвергнутые обещания с ошибкой "возможно необработанный отказ". Но мы обрабатываем отклонение во второй функции, которая вызывает нашу службу ошибок.

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

11 59

11 ответов:

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

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);

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

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

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

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")));

Если вы запустите его в узле, который также соответствует обещаниям/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

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

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

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

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

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

Ссылки:

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

Возможно необработанное отклонение в угловом 1.6

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

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

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

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

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

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

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

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

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

Чтобы избежать необходимости вводить дополнительные .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);
        };
    }
};

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

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

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

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

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

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

Вместо

$q.all([request1, request2]).then(...)
Я надеюсь, что это может сэкономить кому-то немного времени.