Понимание javascript-обещаний; стеки и цепочки

Я столкнулся с двумя проблемами с javascript-обещаниями, особенно со сложными цепочками.

Может ли кто-нибудь объяснить мне разницу (если она есть!) Между этими различными реализациями?

ОСУЩЕСТВЛЕНИЕ 1

var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }).then(function(response) { console.log('2', response); return true; }).then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }).then(function(response) { console.log('4', response); return async4(); }) 

ОСУЩЕСТВЛЕНИЕ 2

 var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }); serverSidePromiseChain.then(function(response) { console.log('2', response); return true; }) serverSidePromiseChain.then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }) serverSidePromiseChain.then(function(response) { console.log('4', response); return async4(); }) 

ОСУЩЕСТВЛЕНИЕ 3

 var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('2', response); return true; }) serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }) serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('4', response); return async4(); }) 

Изменит ли факт, что часть цепочки возвращает значение («true» на шаге 2)? Пообещайте, чтобы все возвращаемые значения были асинхронными обещаниями сохранить поведение?

    Вы иллюстрируете разницу между цепочкой и ветвлением. Цепочка последовательности wil несколько асинхронных операций, так что один начинается, когда предыдущий заканчивается, и вы можете связать произвольное количество элементов с последовательностью один за другим.

    Ветвление перехватывает несколько асинхронных операций для всех в полете одновременно с завершением одной операции триггера.

    Реализации 1 и 3 одинаковы. Они прикованы. Реализация 3 просто использует временную переменную для цепочки, тогда как реализация 1 просто использует возвращаемое значение из .then() напрямую. Никакой разницы в исполнении. Эти .then() обработчики будут вызываться последовательно.

    Реализация 2 отличается. Он разветвлен, не прикован. Поскольку все последующие обработчики .then() привязаны к точному же обещанию serverSidePromiseChain , все они ждут только для того, чтобы первое promise было разрешено, а затем все последующие операции async все в полете в одно и то же время (не серийно, как в двух других опции).


    Может быть полезно понять это, чтобы погрузиться на один уровень вниз, как это работает с обещаниями.

    Когда вы это делаете (сценарии 1 и 3):

     p.then(...).then(...) 

    Что происходит, так это:

    1. Интерпретатор принимает вашу переменную p , находит на ней метод .then() и вызывает ее.
    2. Метод .then() просто сохраняет обратный вызов, который был передан, а затем возвращает новый объект обещания. В настоящее время он не вызывает обратный вызов. Этот новый объект обещания привязан как к исходному объекту обещания, так и к обратному сообщению, которое он хранит. Он не будет разрешаться, пока оба не будут удовлетворены.
    3. Затем .then() второй обработчик .then() на этом недавно возвращенном обещании. Опять же, обработчик .then() по этому обещанию просто сохраняет обратные вызовы .then() и они еще не выполнены.
    4. Затем, когда-то в будущем, первоначальное promise p будет устранено его собственной асинхронной операцией. Когда он будет разрешен, он затем вызывает любые обработчики resolve которые он хранит. Одним из этих обработчиков будет обратный вызов первого обработчика .then() в указанной цепочке. Если этот обратный вызов заканчивается и возвращает либо ничего, либо статическое значение (например, не возвращает само promise), тогда он разрешит promise, которое оно создало для возврата после того, как был вызван .then() . Когда это promise будет разрешено, оно затем вызовет обработчики разрешения, установленные вторым обработчиком .then() выше и так далее.

    Когда вы это сделаете (сценарий 2):

     p.then(); p.then(); 

    В одном обещании p хранится обработчики разрешения из вызовов .then() . Когда это оригинальное promise p будет разрешено, он будет вызывать оба обработчика .then() . Если сами обработчики .then() содержат asynchronous код и возвращают обещания, эти две асинхронные операции будут выполняться одновременно (параллельное поведение), а не в последовательности, как в сценариях 1 и 3.

    Реализация # 1 и # 3 эквивалентна. Реализация №2 отличается тем, что там нет цепочки, и все обратные вызовы будут выполняться по тому же обещанию.

    Теперь давайте немного поговорим о цепочках обещаний. Спецификации говорят, что:

    2.2.7, then необходимо вернуть promise
    2.2.7.1 Если либо onFulfilled либо onRejected возвращает значение x , запустите процедуру разрешения обещаний [[Resolve]](promise2, x)
    2.3.3 Если x является promiseм, принять его состояние

    В основном вызов then по обещанию возвращает другое promise , которое получает разрешение / отклонение на основе callback return value . В вашем случае вы возвращаете скалярные значения, которые затем распространяются по цепочке до следующего обещания.

    В вашем конкретном случае, вот что происходит:

    • # 1: у вас есть 7 обещаний ( async вызов плюс 4, а then два из async3() / async4 ), serverSidePromiseChain укажет на последнее promise, возвращенное к тому then . Теперь, если promise, возвращенное async() , никогда не разрешается / отклоняется, тогда serverSidePromiseChain также будет в той же ситуации. То же самое с async3() / async4() если это promise также не разрешено / отклонено
    • # 2: then вызывается несколько раз по тому же обещанию, создаются дополнительные обещания, однако они не влияют на stream приложения. После того, как promise, возвращенное async() будет разрешено, все обратные вызовы будут выполнены, то, что возвратит обратные вызовы, будет отброшено
    • # 3: это эквивалентно # 1, только теперь вы явно проходите по созданным обещаниям. Когда promise async() будет разрешен первый обратный вызов, который разрешит следующее promise с true , второй обратный вызов будет таким же, третий будет иметь возможность преобразовать цепочку в неудачный, если async3() будет отвергнуто, то же самое с обратным вызовом, который возвращает async4() .

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

    Я написал серию статей в своем блоге о обещаниях, один из которых описывает функцию объединения обещаний, которые можно найти здесь ; статья предназначена для ObjectiveC, однако принципы одинаковы.

    Реализация 1 и 3 представляется эквивалентной.

    В реализации 2 последние три функции .then() действуют по одному и тому же обещанию. Метод .then() возвращает новое promise. Значение выполненного обещания не может быть изменено. См. Promises / A + 2.1.2.2 . Ваш комментарий в реализации 2, ожидается, что ответ будет верным, указывает, что вы ожидаете иначе. Нет, response не будет правдой (если только это не было из первоначального обещания).

    Давайте попробуем это. Выполните следующий fragment кода, чтобы увидеть различия:

     function async(){ return Promise.resolve("async"); } function async3(){ return Promise.resolve("async3"); } function async4(){ return Promise.resolve("async4"); } function implementation1() { logContainer = document.body.appendChild(document.createElement("div")); console.log("Implementation 1"); var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }).then(function(response) { console.log('2', response); return true; }).then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }).then(function(response) { console.log('4', response); return async4(); }); } function implementation2() { logContainer = document.body.appendChild(document.createElement("div")); console.log("Implementation 2"); var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }); serverSidePromiseChain.then(function(response) { console.log('2', response); return true; }); serverSidePromiseChain.then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }); serverSidePromiseChain.then(function(response) { console.log('4', response); return async4(); }); } function implementation3() { logContainer = document.body.appendChild(document.createElement("div")); console.log("Implementation 3"); var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('2', response); return true; }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('4', response); return async4(); }); } var logContainer; var console = { log: function() { logContainer.appendChild(document.createElement("div")).textContent = [].join.call(arguments, ", "); } }; onload = function(){ implementation1(); setTimeout(implementation2, 10); setTimeout(implementation3, 20); } решений1 function async(){ return Promise.resolve("async"); } function async3(){ return Promise.resolve("async3"); } function async4(){ return Promise.resolve("async4"); } function implementation1() { logContainer = document.body.appendChild(document.createElement("div")); console.log("Implementation 1"); var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }).then(function(response) { console.log('2', response); return true; }).then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }).then(function(response) { console.log('4', response); return async4(); }); } function implementation2() { logContainer = document.body.appendChild(document.createElement("div")); console.log("Implementation 2"); var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }); serverSidePromiseChain.then(function(response) { console.log('2', response); return true; }); serverSidePromiseChain.then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }); serverSidePromiseChain.then(function(response) { console.log('4', response); return async4(); }); } function implementation3() { logContainer = document.body.appendChild(document.createElement("div")); console.log("Implementation 3"); var serverSidePromiseChain; serverSidePromiseChain = async().then(function(response) { console.log('1', response); return response; }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('2', response); return true; }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('3', response); // response expected to be 'true' return async3(); }); serverSidePromiseChain = serverSidePromiseChain.then(function(response) { console.log('4', response); return async4(); }); } var logContainer; var console = { log: function() { logContainer.appendChild(document.createElement("div")).textContent = [].join.call(arguments, ", "); } }; onload = function(){ implementation1(); setTimeout(implementation2, 10); setTimeout(implementation3, 20); } 
     body > div { float: left; font-family: sans-serif; border: 1px solid #ddd; margin: 4px; padding: 4px; border-radius: 2px; } 
    Interesting Posts

    CSS: как иметь позицию: абсолютный div внутри позиции: относительный div не обрезается переполнением: скрыто на контейнере

    В Scala, что такое «ранний инициализатор»?

    NodeJS / express: код состояния кэша и 304

    Spring MVC + JSON = 406 Не допускается

    Как разрешены имена серверов сертификатов SSL / Можно ли добавлять альтернативные имена с помощью keytool?

    Что означают значки стрелок в подзаголовке?

    RTL8188CUS AP и клиентский режим одновременно с hostapd в Linux?

    Как настроить цвет и текст режима действия?

    Можете ли вы подключить внешние жесткие диски USB в системе RAID-стиля?

    Лучший способ автоматически переносить тесты с JUnit 3 на JUnit 4?

    Ближайшая точка к данной точке

    SDK с расширенной реальностью с OpenCV

    Папки, переименованные в Проводник Windows, сохраняют исходное имя

    Публикация документов в коллекции клиенту meteor в зависимости от наличия конкретного документа в другом compilationе (публикация с отношениями)

    Неверные формы MVC LoginUrl

    Давайте будем гением компьютера.