Мне сложно понять разницу между помещением .catch BEFORE и AFTER во вложенное обещание.

Вариант 1:

test1Async(10).then((res) => {
  return test2Async(22)
    .then((res) => {
      return test3Async(100);
    }).catch((err) => {
      throw "ERROR AFTER THEN";
    });
}).then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});

Альтернатива 2:

test1Async(10).then((res) => {
   return test2Async(22)
     .catch((err) => {
        throw "ERROR BEFORE THEN";
      })
      .then((res) => {
        return test3Async(100);
      });
  }).then((res) => {
    console.log(res);
  }).catch((err) => {
    console.log(err);
  });

Поведение каждой функции следующее: test1 терпит неудачу, если число <0 test2 терпит неудачу, если число > 10, и test3 терпит неудачу, если число не 100. В этом случае test2 не работает.

Я попытался запустить и сделать test2Async неуспешным, и ДО, и ПОСЛЕ затем ведут себя одинаково, и это не выполняет test3Async. Может кто-нибудь объяснить мне главное отличие размещения улова в разных местах?

В каждой функции I console.log ('Running test X'), чтобы проверить, выполняется ли она.

Этот вопрос возникает из-за моей предыдущей ветки Как превратить вложенный обратный вызов в обещание?. Я полагаю, что это другая проблема и стоит опубликовать другую тему.

Zanko

Ответы (2)

Итак, в основном вы спрашиваете, в чем разница между этими двумя (где p - обещание, созданное из некоторого предыдущего кода):

return p.then(...).catch(...);

и

return p.catch(...).then(...);

Существуют различия, когда p разрешает или отклоняет, но значение этих различий зависит от того, что делает код внутри обработчиков .then () или .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 () (таким образом «обрабатывая» ошибку), то цепочка обещаний переключается в разрешенное состояние и . Затем () обработчик после вызова .catch ().

Вот и разница №2. Если обработчик .catch () установлен ПЕРЕД, то он может обработать ошибку и разрешить вызов обработчику .then ().

Когда использовать:

Используйте первую схему, если вам нужен только один обработчик .catch (), который может перехватывать ошибки либо в исходном обещании p, либо в .then () * Обработчик 100007 * и отклонение от p должны пропускать обработчик .then ().

Используйте вторую схему, если вы хотите иметь возможность отлавливать ошибки в исходном обещании p и, возможно (в зависимости от условий), разрешить цепочке обещаний продолжаться, как разрешено, таким образом выполняя .then () обработчик.

Другой вариант

Есть еще один вариант использования обоих обратных вызовов, который вы можете передать в .then () как в:

 p.then(fn1, fn2)

Это гарантирует, что будет вызван только один из fn1 или fn2. Если p разрешается, то будет вызван fn1. Если p отклоняет, то будет вызван fn2. Никакое изменение результата в fn1 не может привести к вызову fn2 или наоборот. Итак, если вы хотите быть абсолютно уверены, что только один из ваших двух обработчиков вызывается независимо от того, что происходит в самих обработчиках, вы можете использовать p.then (fn1, fn2).

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

return p.then(...).catch(...);

аналогичен синхронному:

try {
  iMightThrow() // like `p`
  then()
} catch (err) {
  handleCatch()
}

Если iMightThrow () не выбрасывает, будет вызвана , тогда (). Если он выбрасывает (или если then () выбрасывает сам), то будет вызван handleCatch (). Обратите внимание, что блок catch не контролирует, вызывается ли , а затем.

С другой стороны,

return p.catch(...).then(...);

аналогичен синхронному:

try {
  iMightThrow()
} catch (err) {
  handleCatch()
}

then()

В этом случае, если iMightThrow () не выдает, то then () выполнится. Если он действительно выбрасывает, тогда до handleCatch () может решить, вызывается ли then (), потому что если handleCatch () перебрасывает, то then () не будет вызываться, поскольку исключение будет немедленно передано вызывающему. Если handleCatch () может корректно обработать проблему, будет вызвано then ().

2022 WebDevInsider