Рубрики
Без рубрики

Сага асинхронного JavaScript: обещания

Вступление мы изучали асинхронные шаблоны JavaScript таким образом, чтобы он теперь сделал … Tagged с JavaScript, программированием, WebDev, Architecture.

вступление

Мы изучали асинхронные шаблоны JavaScript таким образом, что теперь это должно иметь смысл, почему Обратный вызов Часто может быть недостаточным решением наших повседневных проблем и того, как они помогли Thunks Развиваться в мощный, легкий инструмент. Хотя это не решило Проблемы доверия и Инверсия контроля Проблема, уроки, которые мы извлекли, в конечном итоге привели к рождению следующей схемы – Обещания Анкет

Объясняя подход

Вооружившись концептуальным пониманием и знаниями об инновациях и недостатках Thunks, мы теперь готовы взглянуть на то, какие обещания могут предложить нам. Мы не собираемся глубоко погрузиться в обещание API и сразу же перегружать себя этими причудливыми методами и свойствами. В конце дня конкретные названия методов и дизайнерские решения могут отличаться между реализациями, но основная идея всегда останется прежней. Сначала мы рассмотрим концепцию и посмотрим, как текущий JavaScript выражает ее с точки зрения API.

Заполнитель

Что будет хорошим примером обещаний в реальном мире? Похоже, это довольно простая вещь, чтобы объяснить. Давайте представим себя приезжаем в ресторан. Большинству из нас нравится какие -то гамбургеры, не так ли? Итак, вы приходите и заказываете один. Что вы обычно получаете взамен? Квитанция с номером заказа. В конце концов вы собираетесь обменять квитанцию на бургер, когда заказ будет готов, но до тех пор вы сможете с уверенностью думать и начать рассуждать об этом, как будто он уже был в ваших руках. Квитанция стала Заполнитель для будущий бургер Анкет Обещания очень похожи на это. За какую -то ценность, которая будет выполнена в будущем, вам даст заполнитель – A Обещание – что позже можно «обменять» на реальную ценность.

Инверсия контроля: третий раунд

Похоже, что как набое, так и обещания следуют аналогичной философии – они предоставляют вам что -то С чем вы можете работать, пока не появится реальное значение. Но у нас была проблема Инверсия контроля с толчками, потому что они использовали обратные вызовы под капотом. Мы прошли функцию и надеялись на лучшее. Как вы могли бы «смягчить» инверсию контроля? Что если бы мы будем контролировать выполнение кода, который будет работать после готовности значения? Давайте повторем глупой пример, который мы изобрели, чтобы проиллюстрировать, насколько серьезной может возникнуть эта проблема:

fancyAsyncFunctionFromLibrary(function () {
    chargeCreditCard()
})

Псевдокод на спасение

Мы еще не собираемся использовать API текущего обещания, чтобы помочь себе решить эту проблему. Представьте, что у вас вообще нет обещаний. Сгиб клетки мозга и попытайтесь придумать способ решить инверсию проблемы контроля в этом коде с помощью псевдокода. Как бы мы изменили пример выше, чтобы получить контроль над выполнением наших обратных вызовов. К счастью, в программировании есть много шаблонов, которые могут вас вдохновить. Как насчет Мероприятие Излучатели ?

const futureValuePlaceholder = fancyAsyncFunctionFromLibrary()

futureValuePlaceholder.on('complete', chargeCreditCard);

Мы сделали себя FancyAsyncfunctionfromlibrary который теперь возвращает излучатель событий. Учитывая знание того, какие события вы можете получить, мы можем прикрепить наши обратные вызовы, как хотим. В этом примере мы запускаем наш обратный вызов после того, как что -то будет завершено в этой функции, чтобы мы могли взимать кредитную карту. Мы могли бы подписаться на событие ошибки таким же образом. Или мы могли бы решить не делать этого. Мы могли бы даже представить, что мы отсоединяем нашего слушателя, как только уволится полное событие. Есть много вещей, которые мы можем сделать, используя эту модель. Псевдокод, который мы написали в основном, говорит: «Дайте мне объект, который стреляет в разные события, и я решу, на какие события я буду подписаться, и как я буду выполнять свои функции в ответ на них». И интересная часть, он не выглядит так, как обещания, которые мы используем каждый день. Вместо на Метод у нас есть Тогда , что на самом деле знает, какое событие он должен подписаться на ваш обратный вызов. Несмотря на то, что обратные вызовы по -прежнему являются важной частью нашего кода, мы смогли восстановить управление выполнением и выполнить наши функции на наших терминах, используя хороший и чистый API. Подводя итог, еще один способ придумать обещания, это то, что Они очень похожи на эмиттеры событий Анкет Но чтобы решить инверсию контрольной катастрофы, нам нужно что -то большее, чем API. Есть недостающая часть.

Доверие применения

Мы все еще можем быть сомневаемся в том, как будут выполняться наши обратные вызовы. Существует список с достойным количеством проблем по поводу обратных вызовов, которые угрожающе стоят рядом с нашим новорожденным излучателем событий. Нам отчаянно нужно доверять, чтобы быть введенным, чтобы устранить их. Обещания не были бы полезны, если бы они не включали Доверительные механизмы Анкет К счастью, когда вы используете обещания в текущем JavaScript, JavaScript гарантирует, что:

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

Довольно аккуратно, а? Налив четко определенное и строгое поведение, мы больше не спрашиваем себя о том, как выполняются наши обратные вызовы. неизменный Часть также очень важна. JavaScript гарантирует, что, когда вы передаете свое обещание стороннему коду, он никак не может каким -то образом измениться или измениться. Вы просто не можете повлиять как на состояние обещания, так и на ценность внутри. Нет действие на расстоянии . Также наш код теперь безопасен от того, что их называют несколько раз, и мы всегда получаем ошибку, несмотря ни на что. Даже если вы явно не обрабатываете эту ошибку в своем обещании, она будет пузыриться как Неотъемлемое обещание отказ И вы не пропустите компилятор, кричащий на вас.

Покажите нам обещания, сэр

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

fancyAsyncFunctionFromLibraryWithPromise () {
    return new Promise((resolve, reject) => {
        fancyAsyncFunctionFromLibrary(resolve)
    })
}

fancyAsyncFunctionFromLibraryWithPromise()
    .then(chargeCreditCard)
    .catch(handleError)

Наш FancyAsyncfunctionfromlibrary Теперь возвращает обещание, которое мы создали сами. Вы получаете Первоклассник Объект, который вы можете передать, как и любое другое значение. При построении обещания вы передаете ему обратный вызов, который ожидает два аргумента: a решать и отклонить функции. Это ваши инструменты, чтобы переключить состояние обещания на полное состояние или отклоненное. Мы называем Тогда Метод подключения обратного вызовов, который будет выполнен после того, как обещание будет полным, другими словами, функция разрешения была вызвана внутри нашего обещания. Этот обратный вызов получает стоимость обещания, если есть. На противоположной стороне есть метод улова для обработки ошибок, который работает аналогичным образом. Мы должны справиться только с двумя возможными случаями, и у нас есть два соответствующих метода, которые нам нужны. Сам код читается так же, как человеческий язык: «сделай что -то, что требует времени, а затем передай его этой функции, но если что -то пошло не так, поймай ошибку и передай ее этой функции».

Управление потоком

Давайте попробуем сами в написании некоторой последовательности операций, используя обещания, и посмотрим, как они выглядят в немного более распространенном примере:

readFileOnePromise
    .then(fileContents => {
        console.log('first file', fileContents)

        return readFileTwoPromise
    })
    .then(fileContents => {
        console.log('second file', fileContents)

        return readFileThreePromise
    })
    .then(fileContents => {
        console.log('third file', fileContents)
    })

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

Цепочка

Цепочка – это своего рода синтаксис, который позволяет вам выполнять несколько вызовов метода объекта без промежуточных переменных. Это достигается с помощью каждого метода, возвращающего объект. Внутри Тогда Вызов метода вы можете вернуть обещание или значение. В случае, если вы вернули обещание, следующий Тогда не будет увольнять свой обратный вызов, пока это обещание не будет решено. Вы можете обрабатывать обоих одинаковых способов, и это приводит к тому, что время независимая стоимость обертки очень похожа на Thunks. Но часто именно API заставляет людей использовать обещания и думать, что они являются серебряной пулей в мире асинхрового программирования. Помните, что важной частью обещаний является не их API, а их идея и концепция, которые в некоторое время в прошлом инновали в том, как вы работаете с асинхронным кодом в своих программах. Речь идет об их способности, наконец, решить инверсию проблемы контроля, сохраняя при этом преимущества быть контейнером вокруг данных, которые вы можете передать, и заполнителя для будущей ценности.

Обратные вызовы .. снова?

Да, у нас все еще есть обратные вызовы. На самом деле, если вы внимательно посмотрите на обещания, вы увидите, что они могут выглядеть как Менеджеры обратного вызова ! И это третий и последний способ, которым я смог подумать о обещаниях. Они используют обратные вызовы для тех же хорошо известных задач – запуск кода после завершения чего -то, и, кроме того, они приносят доверие, которое нам нужно. Важным моментом в обещаниях является то, что они Уменьшите разрыв между асинхронным и синхронизированным кодом еще больше Анкет Есть две очень важные вещи в синхронных функциях:

  • они возвращают значение
  • Они бросают ошибки

Обещания композиции

Что еще более важно, если мы говорим о функциональный состав Если какая -либо из функций в композиции подает ошибку, эта ошибка обходит все другие слои композиции и выходит вверх, чтобы клиент -код смог бы ее поймать. В случае обратных вызовов, возвращающаяся стоимость была невозможна, поскольку они просто не были готовы в момент вызова. Точно так же вы не могли бросить ошибки, потому что не было никого, чтобы поймать их, и с обратными вызовами вам нужно было бы вручную распространить эти ошибки. Обещания выполняют важную работу по возвращению этих вещей в асинхронный мир, сказав, что каждая функция должна вернуть обещание и гарантировать, что ошибка будет пузыриться. Если написано правильно, те, которые затем/поймать блоки Составьте аналогично их синхронным аналогам Выполнив выполнения, создавая композиционную цепь с отказами, способными прервать ее на любом этапе, которая обрабатывается только кем -то, кто заявляет, что он готов справиться с этим.

Немного функционального программирования

Тогда Метод вместо того, чтобы рассматриваться как «механизм прикрепления обратного вызова», можно рассматривать как «приложение преобразования». Это в основном позволяет нам применить преобразование в значении внутри обещания и создать новый, который будет передаваться по цепочке. С этой точки зрения, обещания очень похожи на Monads с их способностью цепорить и применять функции на базовых значениях. Хотя нынешний API JavaScript для самого выпускного вечера не на 100% чиста, как хотелось бы функциональные программисты, монадическая природа обещаний вполне очевидно.

Больше модного API

Обещания имеют множество дополнительных методов, чтобы улучшить управление потоком из коробки. Обещание. Все Примет множество обещаний и вернет новое обещание, которое разрешается, когда все обещания будут разрешены. Обещание. Любой похож на то, что он ожидает множество обещаний, но вернет обещание, которое разрешает, по крайней мере, одно обещание разрешено. Если нет разрешенных обещаний, обещание результата отклонено. Я не буду просматривать каждый метод на объекте Promise в JavaScript, но вы, вероятно, поймете эту идею. Обещания также предоставляют вам несколько полезных абстракций, которые помогают вам организовать не одну, а группу обещаний в более сложных сценариях. Как только вы начнете открывать документацию, вы обнаружите, что изобретаете эти абстракции на лету. Не все из них в настоящее время реализованы, но никто не мешает вам использовать библиотеки обещаний сторонних обещаний. Вы даже можете создать его самостоятельно!

Недостатки

Я заметил, что есть некоторые статьи о обещаниях, которые сосредоточены на API -злоупотребление Когда говорят о недостатках. Есть также много из них, которые вообще не говорят о проблемах с обещаниями. Осталось несколько вещей, которые обещания не удалось решить или предоставить. Мое отношение к большинству проблем с обещаниями можно было бы описать как «ах, но это и эта вещь также была бы удобной, в целом это не будет иметь смысла в этом шаблоне». Налив нашего главного врага – Инверсия контроля – Победил, теперь мы только ищем дополнительные функции, чтобы сделать наш набор инструментов завершенным. И вы увидите, что все, что описано ниже, кричат, чтобы другой шаблон был создан для использования вместе с обещаниями. Так что воспринимайте эти очки как «приятно имут», а не «нужно исправить».

Все еще вне основного потока

Это может быть спорным моментом. Хотя обещания уменьшают количество вложенных обратных вызовов, с которыми вы работаете, они не удаляют их полностью. Используя стандартные обещания, у нашего синхронного кода нет возможности «ждать» обещания. Рассмотрим этот пример:

const func = (value) => {
    let promise = somePromiseBasedFunction();

    let promiseValue = ?;
    promise.then(function(result){
        // I can access the value here, but there's
        // no way for me to get it up in the main
        // scope and have `func` return its value
    });

    const finalValue = someOtherFunction(promiseValue);
    return finalValue;
}

Хотя цель обещаний состоит в том, чтобы не блокировать вашу программу, часто нам действительно нужен этот вид механизма, чтобы быть доступным. Это еще больше закроет разрыв между синхронизацией и асинхронным кодом. Techally, это было решено в более поздних версиях JavaScript с Асинхрон/жду , но они основаны на генераторах и подлежат отдельной статье.

Не отменяется

Этот также противоречит идеологии обещаний. Без сомнения, способность отменить обещание с исходящим запросом Ajax была бы очень великой, но это также означало бы, что обещания больше не являются неизменными, и вдруг мы теперь уязвимы к проблеме «действия на расстоянии».

Отсутствующие абстракции

Просто «приятно иметь», что часто заставляет вас создавать эти методы с нуля или использовать стороннюю библиотеку в качестве альтернативы. Список доступных абстракций обещаний, реализованных в настоящее время, может чувствовать себя немного ограничивающим в некоторых случаях. Например, представьте, что вы цепочете 10 Тогда звонит и пытается помнить, что каждый раз вам нужно вернуть обещание сделать композицию. Это может легко стать раздражающим и подверженным ошибкам при работе с длинной цепью. Как насчет последовательность Метод, который примет переменное количество функций и сделает это для вас? Он автоматически направит эти функциональные вызовы и гарантирует, что каждый из них вернет все, что нужно, чтобы заставить его работать. Как я уже сказал, можно было бы придумать, по крайней мере, несколько полезных методов, которые не представлены в текущем API, и было бы здорово, если бы они реализовали на самом языке.

Опередить

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

Оригинал: “https://dev.to/romansarder/the-saga-of-async-javascript-promises-2n3i”