Угловые обещания: запускать catch() из оператора then()?

Можно ли запустить часть catch(...) цепочки обещаний из части then(...)?

Например, я делаю запрос $http и связываю некоторое поведение. $http разрешается успешно, но после обработки данных становится ясно, что данные больше подходят для случая ошибки, поэтому вместо этого мы хотим активировать обработчик ошибок.

Проблема в том, что эта цепочка обещаний используется в двух местах; один находится внутри самой службы, а другой — в контроллере, который активировал службу. Контроллер обрабатывает часть catch(...) цепочки обещаний, где он открывает модальное окно, отображающее сообщение об ошибке.

До сих пор мне удавалось связать промис таким образом, что всякий раз, когда в службе запускается then(...) или catch(...), я могу вернуть результат, и затем он будет запущен в контроллере — как и ожидалось.

Но как мне иметь триггер then(...) в сервисе, но возвращать результат, чтобы catch(...) вместо этого срабатывал в контроллере?

Я попытался использовать $q.reject(...) для создания и возврата нового обещания в качестве возвращаемого значения из функции then(...), но это, похоже, не сработало.

Пример:

var url = 'http://google.com';
$http.get(url).then(handleFirst).then(handleSecond).catch(error);

function handleFirst (response) {
    console.log("HandleFirstCalled", response);
    return response;
}

function handleSecond (response) {
    console.log("HandleSecondCalled", response);
    return response;
}

function error (response) {
    console.log("ErrorCalled", response);
}

Как получить handleFirst(...), пропустить выполнение handleSecond(...) и вместо этого выполнить error(...)? Примечание: вы не можете просто вызвать error(response), потому что к нему нет доступа из внешней цепочки обещаний.

[Изменить:] Решение найдено, return $q.reject(response); работает. Однако функция Service catch(...) должна всегда return $q.reject(response). Раньше у меня было просто return response;, которое продолжалось цепочкой промисов контроллера. Но тогда контроллер активирует then(...) в своей цепочке.

Итак, с return response; получилось:

Service -> $http -> then(...) -> catch(...) -> Controller -> then (...)

Изменяя его return $q.reject(response);, получается:

Service -> $http -> then(...) -> catch(...) -> Controller -> catch (...)


person ngDeveloper    schedule 18.06.2015    source источник
comment
Вам нужно показать часть кода. return $q.reject(...) должно хватить   -  person Phil    schedule 19.06.2015
comment
Как сказал @Phil, return $q.reject должен работать, сегодня я ответил на аналогичный вопрос stackoverflow.com/questions/30924047/   -  person Chandermani    schedule 19.06.2015
comment
Как насчет $http.get(url).then(handleFirst).then(handleSecond, error)?   -  person Phil    schedule 19.06.2015
comment
@Фил @Чандермани Спасибо, это работает. Я делал это неправильно. Сначала я сделал что-то вроде var deferred = $q.deferred; deferred.reject(response); return deferred.promise;. Я не знал, что вы можете использовать $q.reject(...) напрямую.   -  person ngDeveloper    schedule 19.06.2015
comment
Вот почему вы всегда должны использовать фактический код в своих вопросах, если он не работает так, как вы ожидаете.   -  person Phil    schedule 19.06.2015
comment
В качестве альтернативы просто throw ошибка в обратном вызове then   -  person Bergi    schedule 19.06.2015
comment
@Phil Не всегда вариант из-за юридических ограничений работодателя. Но спасибо за вашу помощь!   -  person ngDeveloper    schedule 19.06.2015
comment
@Bergi Берги Я тоже пробовал что-то подобное, но у меня не получилось. Вы имеете в виду что-то вроде return new throw Error(response); или как?   -  person ngDeveloper    schedule 19.06.2015
comment
@ngDeveloper, по крайней мере, те же структуры управления. Код в вашем вопросе вообще не упоминает $q.defer, но в комментариях мы узнаем, что вы на самом деле используете.   -  person Phil    schedule 19.06.2015
comment
@ngDeveloper: это синтаксическая ошибка. Я имею в виду throw new Error(response);   -  person Bergi    schedule 19.06.2015


Ответы (1)


У вас есть два варианта в Angular, чтобы отклонить возвращенное обещание из then.

throw new Error(...); // this will reject the promise and trigger $exceptionHandler

Or:

return $q.reject(new Error(...)); // this will reject the promise

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

Обратите внимание, что в стандартных (обещаниях ES6) и других совместимых обещаниях (например, Bluebird) это различие между выбросом и отклонением не делается.

person Benjamin Gruenbaum    schedule 19.06.2015