Итак, в основном вы спрашиваете, в чем разница между этими двумя (где p
обещание, созданное из некоторого предыдущего кода):
return p.then(...).catch(...);
и
return p.catch(...).then(...);
Существуют различия, когда p разрешает или отклоняет, но значение этих различий зависит от того, что делает код внутри обработчиков .then()
or .catch()
.
Что происходит при p
разрешении:
В первой схеме при p
разрешении .then()
вызывается обработчик. Если этот .then()
обработчик возвращает значение или другое обещание, которое в конечном итоге выполняется, .catch()
обработчик пропускается. Но если .then()
обработчик либо бросает, либо возвращает обещание, которое в конечном итоге отклоняет, тогда .catch()
обработчик выполнит как отклонение в исходном обещании p
, так и ошибку, которая возникает в .then()
обработчике.
Во второй схеме при p
разрешении .then()
вызывается обработчик. Если этот .then()
обработчик либо выбрасывает, либо возвращает обещание, которое в конечном итоге отклоняет, то .catch()
обработчик не может его поймать, потому что он находится перед ним в цепочке.
Итак, это отличие №1. Если .catch()
обработчик AFTER, он также может перехватывать ошибки внутри .then()
обработчика.
Что происходит при p
браке:
Теперь, в первой схеме, если обещание p
отклоняется, то .then()
обработчик пропускается, и .catch()
обработчик будет вызван, как и следовало ожидать. То, что вы делаете в .catch()
обработчике, определяет, что будет возвращено в качестве окончательного результата. Если вы просто возвращаете значение из .catch()
обработчика или возвращаете обещание, которое в конечном итоге разрешается, тогда цепочка обещаний переходит в разрешенное состояние, потому что вы «обработали» ошибку и вернулись нормально. Если вы выбрасываете или возвращаете отклоненное обещание в .catch()
обработчике, то возвращенное обещание остается отклоненным.
Во второй схеме, если промис p
отклоняется, .catch()
вызывается обработчик. Если вы возвращаете нормальное значение или обещание, которое в конечном итоге разрешается от .catch()
обработчика (таким образом «обрабатывая» ошибку), то цепочка обещаний переключается в разрешенное состояние, и будет вызван .then()
обработчик после .catch()
.
Итак, это различие №2. Если .catch()
обработчик - BEFORE, он может обработать ошибку и разрешить .then()
вызов обработчику.
Когда использовать:
Используйте первую схему, если вам нужен только один .catch()
обработчик, который может перехватывать ошибки либо в исходном обещании, p
либо в .then()
обработчике, и отклонение от p
должно пропускать .then()
обработчик.
Используйте вторую схему, если вы хотите иметь возможность отлавливать ошибки в исходном обещании p
и, возможно, (в зависимости от условий) разрешить цепочке обещаний продолжать работу в разрешенном состоянии, таким образом выполняя .then()
обработчик.
Другой вариант
Есть еще один вариант использования обоих обратных вызовов, который вы можете передать, .then()
как в:
p.then(fn1, fn2)
Это гарантирует, что будет вызван только один из fn1
или fn2
. Если p
разрешится, то fn1
будет вызван. Если p
откажется, то fn2
будет называться. Никакое изменение результата не fn1
может заставить вас fn2
ответить, или наоборот. Итак, если вы хотите быть абсолютно уверены, что вызывается только один из двух ваших обработчиков, независимо от того, что происходит в самих обработчиках, вы можете использовать p.then(fn1, fn2)
.