Я вижу документы для finally Bluebird, но до сих пор не совсем понимаю разница против then.

Чтобы было ясно: я точно знаю, почему then вызывается после catch. Я хочу вызвать его после перехвата. Это намерение. У меня вопрос: если я хочу код всегда выполнять независимо от состояния обещания, в чем разница между then и finally для этого?

Я построил этот тест:

var Promise = require("bluebird");

function test1 () {
    console.log("RESOLVE + THEN + CATCH + THEN");
    return new Promise((resolve, reject) => resolve())
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .then(() => console.log("end"));
}

function test2 () {
    console.log("REJECT + THEN + CATCH + THEN");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .then(() => console.log("end"));
}

function test3 () {
    console.log("RESOLVE + THEN + CATCH + FINALLY");
    return new Promise((resolve, reject) => resolve())
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .finally(() => console.log("end"));
}

function test4 () {
    console.log("REJECT + THEN + CATCH + FINALLY");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .finally(() => console.log("end"));
}

// run tests "sequentially" so console output doesn't get blended
setTimeout(test1, 500);
setTimeout(test2, 1000);
setTimeout(test3, 1500);
setTimeout(test4, 2000);

Это тестирует четыре случая:

  1. .then(...).catch(...).then(...) с решенным обещанием.
  2. .then(...).catch(...).then(...) с отклоненным обещанием.
  3. .then(...).catch(...).finally(...) с решенным обещанием.
  4. .then(...).catch(...).finally(...) с отклоненным обещанием.

Результаты, которые я вижу, являются случаями 1 + 2, ведущими себя идентично 3 + 4: последний бит (then или finally в зависимости от теста) выполняется независимо от того, что происходит перед ним, как и предполагалось. Результат этой программы:

RESOLVE + THEN + CATCH + THEN
then
end
REJECT + THEN + CATCH + THEN
error: rejected
end
RESOLVE + THEN + CATCH + FINALLY
then
end
REJECT + THEN + CATCH + FINALLY
error: rejected
end

Теперь я спрашиваю, потому что увидел прокомментируйте другой вопрос, который я задал:

Не уверен, что ваши обещания поддерживают это, но вы должны изменить последний .then на .finally, чтобы busy всегда очищался.

Из моих очень ограниченных знаний then и тестов, приведенных выше, кажется, что then достаточно. Но после этого комментария я подвергаю сомнению себя и безопасность использования then для выполнения кода "finally".

Итак, мой вопрос: в чем разница между then и finally? Они выглядят так, будто ведут себя одинаково, но когда мне нужно будет использовать finally вместо then?

13
Jason C 13 Дек 2016 в 23:39

3 ответа

Лучший ответ

Первое отличие: иногда вы не хотите отлавливать ошибки в том месте, где они возникают, а в коде, который использует эту функцию, поэтому вы их не отлавливаете. В этом случае вы не можете заменить then() и finally().

Иногда вам нужно что-то исправить независимо от того, произошла ошибка или нет (обнуление ссылок, очистка тайм-аутов и тому подобное). Вот где вы используете finally().

Второе отличие: функция, которую вы передаете catch(), также может быть сгенерирована, тогда вы получите отклоненное обещание, а следующий then() не будет вызван.

(итак, перед тем как поймать все еще будет выполнено сообщение об ошибке, я не знал этого)

Да, в этом смысл finally(). Он будет выполнен при любых обстоятельствах без изменения разрешенного значения.

Возможно, вы захотите немного прочитать / google о try {} finally {} без улова.

15
Matthew Read 14 Сен 2017 в 04:02

.then и .finally не совпадают.

.then - главное примитивное обещание. Это именно то, что определено в Promises / A + spec, и все библиотеки обещаний будут реализовывать его.

.finally обработчик Bluebird будет «вызываться независимо от судьбы обещания». Таким образом, необработанное исключение все еще вызывает .finally.

new Promise((resolve, reject) => reject(false))
  .finally(a => console.log('finally', a))
// finally undefined
// Unhandled rejection false

new Promise((resolve, reject) => reject(false))
  .then(a => console.log('then', a))
// Unhandled rejection false

.finally не изменит разрешенного значения обещания и не получит результат цепочки обещаний.

new Promise((resolve, reject) => reject(false))
  .catch(e => {
    console.log(e)
    return 2
  })
  .finally(a => {
    console.log('finally', a)
    return 1
  })
  .then(res => console.log('res', res))
// finally undefined
// res 2

Методы выглядят одинаково в ваших тестовых примерах, так как тесты перехватывают все ошибки, и вы используете только обещания для управления потоком, не полагаясь на значения, которые разрешаются / отклоняются в цепочке обещаний.

5
Matt 13 Дек 2016 в 22:26

Хорошо, после некоторой беседы и большой помощи от KevinB, я понял, по крайней мере, одно отличие. Рассмотрим следующие два новых теста:

function test5 () {
    console.log("REJECT + THEN + CATCH/THROW + THEN");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(function(err) { throw new Error("error in catch"); })
       .then(() => console.log("end"));
}

function test6 () {
    console.log("REJECT + THEN + CATCH/THROW + FINALLY");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(function(err) { throw new Error("error in catch"); })
       .finally(() => console.log("end"));
}

В них обещание отклонено, но из catch выдается ошибка.

Обещание в конечном итоге отклоняется в обоих случаях, но для finally случая finally все еще выполняется, then - нет.

Так что это разница. Они почти одинаковы за исключением того, что при возникновении ошибки из обработчика catch выполняется finally и {{X2 }} не.

Это означает, что комментарий, который я цитировал, также имеет свои достоинства: если бы в моем обработчике ошибок произошла другая ошибка, then не гарантировал бы очистку, а finally. Это тот случай, которого мне не хватало.

2
Jason C 13 Дек 2016 в 21:18