Обновить:
Чтобы помочь будущим зрителям этого поста, я создал демо-версию ответа Pluma .
Вопрос:
Моя цель кажется довольно простой.
step(1)
.then(function() {
return step(2);
}, function() {
stepError(1);
return $q.reject();
})
.then(function() {
}, function() {
stepError(2);
});
function step(n) {
var deferred = $q.defer();
//fail on step 1
(n === 1) ? deferred.reject() : deferred.resolve();
return deferred.promise;
}
function stepError(n) {
console.log(n);
}
Проблема здесь заключается в том, что, если мне не удается выполнить шаг 1, оба stepError(1)
оператора И stepError(2)
запускаются. Если я этого не сделаю, return $q.reject
то меня не stepError(2)
уволят, а step(2)
будут, что я понимаю. Я достиг всего, кроме того, что я пытаюсь сделать.
Как мне написать обещания, чтобы я мог вызвать функцию при отклонении, не вызывая все функции в цепочке ошибок? Или есть другой способ сделать это?
Вот живая демонстрация, так что у вас есть с чем поработать.
Обновить:
Я вроде решил это. Здесь я перехватываю сообщение об ошибке в конце цепочки и передаю данные, чтобы reject(data)
узнать, какую проблему нужно решить в функции ошибки. Это на самом деле не соответствует моим требованиям, потому что я не хочу зависеть от данных. Это было бы неэффективно, но в моем случае было бы яснее передать функцию обратного вызова с ошибкой, а не зависеть от возвращаемых данных, чтобы определить, что делать.
step(1)
.then(function() {
return step(2);
})
.then(function() {
return step(3);
})
.then(false,
function(x) {
stepError(x);
}
);
function step(n) {
console.log('Step '+n);
var deferred = $q.defer();
(n === 1) ? deferred.reject(n) : deferred.resolve(n);
return deferred.promise;
}
function stepError(n) {
console.log('Error '+n);
}
Promise.prototype.catch()
примеры на MDN показывают решение точно таких же проблем.Ответы:
Причина, по которой ваш код не работает должным образом, заключается в том, что он на самом деле делает что-то отличное от того, что вы думаете.
Допустим, у вас есть что-то вроде следующего:
Чтобы лучше понять, что происходит, давайте представим, что это синхронный код с
try
/catch
blocks:onRejected
Обработчика (второй аргументthen
), по существу , механизм коррекции ошибок (например,catch
блок). Если выдается ошибкаhandleErrorOne
, она будет перехвачена следующим блоком catch (catch(e2)
) и т. Д.Это явно не то, что вы хотели.
Допустим, мы хотим, чтобы вся цепочка разрешений не работала, независимо от того, что пошло не так:
Примечание. Мы можем оставить его там,
handleErrorOne
где он есть, потому что он будет вызываться только в случаеstepOne
отказа (это первая функция в цепочке, поэтому мы знаем, что если цепочка отклонена в этой точке, это может быть только из-за обещания этой функции) ,Важным изменением является то, что обработчики ошибок для других функций не являются частью основной цепочки обещаний. Вместо этого у каждого шага есть своя «подцепь»,
onRejected
которая вызывается только в том случае, если шаг был отклонен (но не может быть достигнут основной цепочкой напрямую).Причиной этого является то, что оба
onFulfilled
иonRejected
являются необязательными аргументамиthen
метода. Если обещание выполнено (то есть выполнено), и у следующегоthen
в цепочке нетonFulfilled
обработчика, цепочка продолжится, пока не будет выполнено обещание с таким обработчиком.Это означает, что следующие две строки эквивалентны:
Но следующая строка не эквивалентна двум выше:
Библиотека обещаний Angular
$q
основана наQ
библиотеке kriskowal (которая имеет более богатый API, но содержит все, что вы можете найти$q
). Документация API Q на GitHub может оказаться полезной. Q реализует спецификацию Promises / A + , в которой подробно описывается, какthen
и как работает поведение разрешения обещаний.РЕДАКТИРОВАТЬ:
Также имейте в виду, что если вы хотите разорвать цепочку в своем обработчике ошибок, он должен вернуть отклоненное обещание или выдать ошибку (которая будет автоматически перехвачена и помещена в отклоненное обещание). Если вы не вернете обещание,
then
оберните возвращаемое значение обещанием решимости для вас.Это означает, что если вы ничего не возвращаете, вы фактически возвращаете решенное обещание для значения
undefined
.источник
if you don't return anything, you are effectively returning a resolved promise for the value undefined.
Спасибо @plumastepOne().then(stepTwo, handleErrorOne)
`stepOne (). then (null, handleErrorOne) .then (stepTwo)` Являются ли они полностью эквивалентными? Я думаю, что в случае отклонения воstepOne
второй строке кода будет выполняться,stepTwo
но первая будет только выполнитьhandleErrorOne
и остановить. Или я что-то упустил?Немного опоздал на вечеринку, но у меня сработало это простое решение:
Это позволяет вырваться из цепочки.
источник
.then(user => { if (user) return Promise.reject('The email address already exists.') })
.then(user => { if (user) throw 'The email address already exists.' })
Что вам нужно, так это повторяющаяся
.then()
цепочка с особым случаем для начала и особым случаем для завершения.Хитрость заключается в том, чтобы получить номер шага в случае сбоя, который будет получен в конечном обработчике ошибок.
step(1)
безоговорочно..then()
со следующими обратными вызовами:.then()
без обработчика успеха и окончательный обработчик ошибок.Вы можете написать все это от руки, но проще продемонстрировать шаблон с помощью именованных обобщенных функций:
посмотреть демо
Обратите внимание на то
step()
, как отложенное отклоняется или разрешаетсяn
, таким образом делая это значение доступным для обратных вызовов в следующем.then()
в цепочке. ПослеstepError
вызова ошибка многократно перебрасывается, пока не будет обработанаfinalError
.источник
При отклонении вы должны передать ошибку отклонения, а затем обернуть обработчики ошибок шага функцией, которая проверяет, следует ли обрабатывать отклонение или «перебрасывать» до конца цепочки:
Что бы вы увидели на консоли:
Вот рабочий код https://jsfiddle.net/8hzg5s7m/3/
Если у вас есть особая обработка для каждого шага, ваша оболочка может выглядеть примерно так:
тогда твоя цепь
источник
Если я правильно понимаю, вы хотите, чтобы только ошибка показывалась на ошибочном шаге, верно?
Это должно быть так же просто, как изменить случай неудачи первого обещания следующим образом:
Вернувшись
$q.reject()
в случае неудачи первого шага, вы отклоняете это обещание, что приводит к вызову errorCallback во втором шагеthen(...)
.источник
step(2)
. Сейчас я просто попробовал еще раз, этого не происходит. Я весьма озадачен.return step(2);
должна вызываться только приstep(1)
успешном разрешении.return $q.reject()
, цепь будет продолжать работать . В этом случае всеreturn response
испортилось. Смотрите это: jsbin.com/EpaZIsIp/6/edithttp://jsbin.com/EpaZIsIp/20/edit
Или автоматизировано для любого количества шагов:
http://jsbin.com/EpaZIsIp/21/edit
источник
deferred.reject(n)
то получу предупреждение, что обещание отклонено с помощью объектаПопробуйте использовать это как libs:
https://www.npmjs.com/package/promise-chain-break
источник
Если вы хотите решить эту проблему, используя async / await:
источник
Присоедините обработчики ошибок как отдельные элементы цепочки непосредственно к выполнению шагов:
или используя
catch()
:Примечание. По сути, это тот же шаблон, который предлагает pluma в своем ответе, но с использованием имен OP.
источник
Найдены
Promise.prototype.catch()
примеры на MDN ниже очень полезно.(В принятом ответе упоминается,
then(null, onErrorHandler)
что в основном то же самое, что иcatch(onErrorHandler)
.)источник
Лучшее решение - провести рефакторинг в вашей цепочке обещаний, чтобы использовать ES6 await's. Затем вы можете просто вернуться из функции, чтобы пропустить остальную часть поведения.
Я бью себя по этому шаблону больше года, и я жду, что это - рай.
источник
Используйте модуль SequentialPromise
умысел
Предоставить модуль, в обязанности которого входит последовательное выполнение запросов, в то же время отслеживая текущий индекс каждой операции обычным образом. Определите операцию в шаблоне команд для гибкости.
участники
execute
метод для цепочки и отслеживания каждой операции. SequentialPromise возвращает Promise-Chain из всех выполненных операций.execute
метод, передавая порядковый список параметров для каждой операции.последствия
Используйте SequentialPromise, когда необходимо порядковое поведение разрешения Promise. SequentialPromise будет отслеживать индекс, для которого обещание было отклонено.
Реализация
Суть
SequentialPromise
источник
Если в какой-то момент вы вернетесь,
Promise.reject('something')
вы будете брошены в блоке улова к обещанию.Если первое обещание не даст никакого результата, вы получите только «Нет результата» в консоли.
источник