Смутить ошибку и отказаться от обещания

Все:

Я новичок в JS Promise, есть одна путаница, когда дело доходит до цепочки Promise, скажем, у меня есть цепочка обещаний вроде:

var p = new Promise(function(res, rej){
})
.then(
    function(data){
    }, 
    function(err){
    })
.then(
    function(data){
    }, 
    function(err){
    })
.catch(
    function(err){
    })

Что меня смущает:

  • Когда функция (err) вызывается и когда вызов catch вызывается?
  • Как разрешить и отклонить в then?

Спасибо

Ответ 1

Формуляр для использования обещания:

var p = new Promise(function(resolve, reject) {

  var condition = doSomething();

  if (condition) {
    resolve(data);
  } else {
    reject(err);
  }

});

Нет ничего особенного в .catch, это просто сахар для .then (undefined, func), но .catch более четко сообщает, что он является чисто обработчиком ошибок.

Если a Promise не разрешает и в нем не предоставляется обратный вызов отклонения, он переходит к следующему .then в цепочке с обратным вызовом отказа. Обратный вызов отклонения - reject(err).

Более подробные объяснения см. в разделе Javascript Promises - снова и снова.


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

Вы можете ограничить себя обратным вызовом отклонения в .catch в конце цепочки .then. Любой Error в любом .then затем перейдет к .catch. Одна тонкость: любая ошибка в .catch не попадает.

Ответ 2

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

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

Если Promise отвергает, вторая функция в вашем первом .then() будет вызвана с отклоненным значением, и любое возвращаемое значение станет новым разрешенным обещанием, которое затем переходит в первую функцию вашего второго. Поймать здесь тоже нельзя. Это только в том случае, если Promise отклоняет и вы отказываетесь от отклонения Promises или бросаете ошибки в ваших функциях function(err){}, которые вы получите в function(err){} в вашем блоке catch.

Чтобы разрешить ваши функции function(data){}, все, что вам нужно сделать, это вернуть значение (или вернуть Promise/thenable, который позже будет разрешен). Чтобы отклонить, вам нужно либо выбросить ошибку, фактически вызвать ошибку, вернуть новое обещание, которое в конечном итоге отклонит, либо явно вернуть Promise.reject(::some value::).

Чтобы разрешить в ваших блоках function(err){}, все, что вам нужно сделать, это вернуть новое значение. Вы также можете вернуть Promise, и в этом случае Promise - это то, что будет возвращено (в конечном счете, разрешение или отклонение).

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

Ответ 3

  • Обратите внимание на пример функции-исполнителя в

    var p = new Promise(function(res, rej){});

    является неполным. Действительная функция-исполнитель, предоставленная конструктору Promise, должна вызвать свой первый аргумент (res), чтобы разрешить построенное обещание или его второй аргумент (rej), чтобы отклонить обещание. Эти вызовы обычно выполняются асинхронно, но не обязательно должны быть в ES6.

  • Когда обещание разрешается с помощью объекта Promise (или любого объекта с свойством .then, который является функцией), ничего не происходит, пока объект обещания, предоставленный в самом разрешении, не станет выполненным или отвергнута. Выполненные значения передаются обработчикам .then onFulfilled, отклоненные значения передаются .then onRejected обработчикам/слушателям/обратным вызовам (в зависимости от вашей терминологии).

  • Но когда обещание разрешено с не обещающим (вроде) объектом, слушатели, представленные в качестве первого параметра .then, вызывают с разрешением.

  • Когда обещание отклоняется с любым значением, вызываемые в качестве второго параметра .then или первый параметр .catch вызываются с отклоненным значением.

  • .catch является эвфемизмом для вызова .then с предоставленным аргументом в качестве второго параметра и опусканием первого параметра, как в

    Promise.prototype.catch = function( listener) { return this.then(null, listener);};

  • Поведение .then зарегистрированных onFulfill и onReject функций одинаково. Отклонить обещанное обещание выдать ошибку. Чтобы выполнить обещание в цепочке, вы получите не обещание. Чтобы сохранить цепочку обещаний, верните обещание (или обещание).


  • (Обновление) Если параметр, предоставленный в .then( onFulfill, onReject) отсутствует или не является объектом функции, обработка эквивалентна предоставлению фиктивной функции из:

    function onFulfill( data) { return data;}
    function onReject( err) { throw err;}
    

    Это обычный случай при вызове then или catch с одним аргументом.