2017-02-02 4 views
21

У меня возникли проблемы с пониманием разницы между помещением .catch ПЕРЕД И ПОСЛЕ, а затем вложенным обещанием.Размещение улова ДО и ПОСЛЕ затем

Вариант 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'), чтобы проверить, выполняется ли она.

Этот вопрос возникает из-за предыдущей темы, которую я опубликовал How to turn nested callback into promise?. Я полагаю, что это другая проблема и стоит опубликовать еще одну тему.

+0

и. И .catch могут изменить обещание ... так что я не уверен, откуда приходит неправильное понимание. Если вы положили catch до. Then, он будет отклонять отклонения, которые произошли до. Then, а затем будет запускаться, это будет выполнено/не выполнено обратное вызовы на основе того, что происходит внутри .catch, и наоборот, когда вы меняете их. –

+0

Извините, если мой вопрос не был ясен. Но в этом случае, как я сказал, оба случая ведут себя одинаково, поэтому я не вижу разницы. Можете ли вы сказать мне, когда мы ставим ловушку раньше, и когда мы решили поставить ее ПОСЛЕ? Полагая это, кажется, действительно интуитивно понятным и обычным явлением. Просто не уверен, почему иногда мы помещаем его до этого времени. – Zanko

+0

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

ответ

45

Так, в принципе, вы спрашиваете, в чем разница между этими двумя (где 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() ПОСЛЕ, он также может ловить ошибки внутри обработчика .then().

Что происходит, когда p отвергает:

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

Во второй схеме, если обещание p отклоняет, то вызывается обработчик .catch(). Если вы возвращаете нормальное значение или обещание, которое в конечном итоге разрешается с помощью обработчика .catch() (таким образом, «обрабатывая» ошибку), то цепочка обещаний переключается в разрешенное состояние и обработчик .then() после вызова .catch().

Так что разница №2. Если обработчик .catch() ПЕРЕД, он может обрабатывать ошибку и разрешать обработчик .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).

+0

Вопрос в частности о порядке '.then()' и '.catch()', на который вы отвечаете. Кроме того, вы даете несколько советов о том, когда использовать какой заказ, где я думаю, что уместно упомянуть третий вариант, а именно передачу как успешного, так и обработчика ошибок в [.then()] (https://developer.mozilla.org/ EN-US/Docs/Web/JavaScript/Справка/Global_Objects/Promise/затем # Параметры). В этом случае будет вызываться не более одного обработчика. – ArneHugo

+0

@ArneHugo - хорошее предложение. Я добавил. – jfriend00

2

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

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

похож на синхронные:

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

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

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

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

похож на синхронные:

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

then() 

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