То, что вы наблюдаете здесь, называется рекурсивным then
разрешением. Процесс разрешения обещаний в спецификации Promises / A + содержит следующее предложение:
onFulfilled или onRejected возвращает значение x, запускает процедуру разрешения обещаний [[Resolve]] (prom2, x)
Спецификация обещания ES6 (обезвреживание обещаний) содержит аналогичное предложение.
Это означает, что когда выполняется операция
resolve
: либо в конструкторе обещаний, вызвавPromise.resolve
или в вашем случае в цепочкеthen
реализация обещания должна рекурсивно разворачивать возвращаемое значение, если это обещание.На практике
Это означает, что если
onFulfilled
(then
) возвращает значение, попробуйте «разрешить» значение обещания самостоятельно, таким образом, рекурсивно ожидая всю цепочку.Это означает следующее:
promiseReturning().then(function(){ alert(1); return foo(); // foo returns a promise }).then(function(){ alert(2); // will only run after the ENTIRE chain of `foo` resolved // if foo OR ANY PART OF THE CHAIN rejects and it is not handled this // will not run });
Итак, например:
promiseReturning().then(function(){ alert(1); return Promise.resolve().then(function(){ throw Error(); }); }).then(function(){ alert("This will never run"); });
И что:
promiseReturning().then(function(){ alert(1); return Promise.resolve().then(function(){ return delay(2000); }); }).then(function(){ alert("This will only run after 2000 ms"); });
Is это хорошая идея?
Это была тема много дискуссий в процессе спецификации обещаний, был обсужден второй цепной метод, который не демонстрирует такого поведения, но решил против (все еще доступен в Chrome, но скоро будет удален ). Вы можете прочитать о всех дискуссиях в этой эдисковой цепочке .
На других языках
Следует упомянуть, что другие языки этого не делают, ни фьючерсы в Scala, ни фьючерсы в Scala или задачи в C # имеют это свойство. Например, в C # вам нужно будет вызвать
Task.Unwrap
в задаче, чтобы дождаться, когда ее цепочка будет разрешена.