В рамках современной инфраструктуры JavaScript обещает чрезвычайно важно с точки зрения передних разработчиков.
Это основа синтаксиса async/await, стандартной формы обработки асинхронности в JavaScript. И будущий веб-API, пока он асинхронный, появится в форме промисов.
Если вы не понимаете знаний и механизма работы Promises, возможно, вы не сможете выполнять ежедневную работу по веб-разработке в будущем.
Поэтому обещания стали одним из обязательных вопросов на фронтенд-интервью. В Интернете вы также можете найти множество технических статей о промисах. Есть даже несколько платных руководств по внешнему интерфейсу, которые научат вас реализовывать спецификации Promises/A+ с нуля в качестве аргумента в пользу продажи.
Promises/A+, есть готовый набор юнит-тестов, легко настроить среду разработки и проверить соответствие кода требованиям спецификации.
Реализация промисов/A+ — полезное упражнение для разработчиков, которые уже понимают промисы.
Однако, если новичок хочет изучить Promises, внедрив Promises/A+. Или подумайте, что после внедрения спецификации Promises/A+ уровень понимания промисов можно качественно улучшить.
Может разочароваться в конце.
На самом деле спецификация Promises/A+ короткая и простая в реализации. Он полон подробных описаний поведения, в нем отсутствует цель проектирования и предыстория, а также вообще не представлены сценарии использования. Не лучший материал для начала работы с Promises.
Даже если вы успешно реализуете спецификацию Promises/A+, вы не обязательно лучше используете функцию Promises, чем разработчик, который ее не реализовал.
Эта статья будет разделена на три части. Первая часть демонстрирует реализацию спецификации Promises/A+ менее чем за 100 строк кода. Вторая часть проясняет несколько мифов разработчиков о промисах. Завершается третья часть.
1. Реализуйте спецификацию Promises/A+
1.1 Предварительная работа
An open standard for sound, interoperable JavaScript promises
По указанному выше адресу вы можете просмотреть содержание спецификации.
Наборы тестов можно загрузить с помощью npm install promises-aplus-tests.
Запустите набор тестов через npm run test.
1.2. Понимание терминологии
Первая часть спецификации описывает значение нескольких терминов.
Обещание — это объект или функция, содержащая метод then, который соответствует поведению, указанному в спецификации.
thenable — это объект или функция, которая содержит метод then.
value — любое допустимое значение JS.
исключение — это значение, выдаваемое оператором throw.
причина — это значение, указывающее, почему обещание было отклонено.
Эту часть не нужно внедрять в код, продолжайте читать.
1.3 Состояние обещания
У обещания есть 3 состояния: ожидание, выполнение и отклонение.
В состоянии ожидания обещание можно переключить на выполненное или отклоненное.
В выполненном состоянии он не может переходить в другие состояния и должен иметь неизменное значение.
В отклоненном состоянии он не может быть перенесен в другие состояния и должен иметь неизменную причину.
Реализовано в коде, вероятно, как указано выше:
Есть 3 константы в ожидании, выполнено, отклонено,
Конструктор Promise со свойствами состояния и результата.
Когда состояние выполнено, результат рассматривается как значение.
Когда состояние отклонено, результат рассматривается как причина.
Функция перехода состояния перехода, которая будет выполнять переход состояния только тогда, когда состояние находится в состоянии ожидания.
Как указано выше, на самом деле не так много места для свободы. Неважно, кто написал это, это просто небольшая разница в именах переменной, строки кода.
1.4.Тогда метод
Промис должен иметь метод then, который принимает параметры onFulfilled и onRejected.
Это похоже на следующее: добавление метода-прототипа.
onFulfilled и onRejected должны выполняться не более одного раза, если они являются функциями.
Параметр onFulfilled — это значение, а параметр функции onRejected — причина.
Метод then можно вызывать много раз, каждый раз регистрируя набор обратных вызовов onFulfilled и onRejected. Если они вызываются, они должны вызываться в том порядке, в котором они были зарегистрированы.
Как и выше, добавление записи массива обратных вызовов для обещания.
Метод then должен возвращать обещание.
Затем реализация обогащается следующим образом:
В методе then верните new Promise(f), который удовлетворяет требованию, которое должно возвращать промис.
Когда состояние находится в ожидании, оно сохраняется в списке обратных вызовов.
Когда состояние не ожидает обработки, оно передается в handleCallback для обработки.
Что касается ручного обратного вызова. На самом деле это не важно, надо только знать, оно должно существовать. Мы должны сделать некоторую обработку, не записывая в функцию THEN, а во внешнюю вспомогательную функцию.
Что касается того, почему вам нужно установить setTimeout?
Потому что в методе then есть еще одно важное ограничение:
onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
Вместо того, чтобы реализовывать промисы на уровне движка JS, мы используем JS для реализации промисов JS. В JS вы не можете активно контролировать свой собственный стек контекста выполнения. Его можно реализовать косвенно через API, такие как setTimeout/nextTick, и здесь выбирается setTimeout.
Обещание, возвращаемое методом then, также имеет собственное состояние и результат. Они будут определены поведением onFulfilled и onRejected.
Это именно то, что делает handleCallback.
Функция handleCallback в зависимости от состояния определяет, следует ли выбрать выполненный путь или отвергнутый путь.
Сначала определите, является ли onFulfilled/onRejected функцией, и если да, используйте их возвращаемое значение в качестве результата следующего обещания.
Если нет, напрямую используйте результат текущего промиса как результат следующего промиса.
Если во время выполнения onFulfilled/onRejected возникает ошибка, эта ошибка используется в качестве причины отклонения следующего промиса.
Основная цель метода then — создать результат следующего обещания.
Наш код почти без дополнительной логики обработки точно реализует поведение, указанное в спецификации.
1.4. Процедура разрешения обещаний
На приведенном выше снимке экрана мы также видим заявление о процедуре разрешения обещаний.
В нем описывается, что при разрешении некоторых специальных значений требуется специальная обработка. Эта специальная обработка также четко описана в спецификации.
Первый шаг — выдать TypeError, если результатом является само текущее обещание.
На втором этапе, если результатом является другое обещание, используйте его состояние и состояние результата.
Третий шаг, если результат является доступным объектом. Сначала возьмите функцию then, затем вызовите функцию then и повторно войдите в процесс Процедура разрешения обещаний.
Наконец, если вышеуказанное не так, этот результат становится результатом текущего промиса.
На фото в коде, как показано выше, напишите 3 ifs в порядке, описанном спецификацией.
Первый, чтобы определить, является ли результат самим промисом, должен выдать ошибку TypeError.
Второй определяет, относится ли результат к типу обещания, а затем вызывает then(resolve, reject), чтобы получить его значение или причину.
В-третьих, определить, является ли результат пригодным для использования объектом, то есть сначала удалить then, а затем использовать новое обещание для входа в процесс процедуры разрешения обещаний.
Если ни то, ни другое, разрешить результат напрямую.
1.5. Интегрируйте оставшиеся части
На данный момент обработаны все важные детали.
1) У нас есть переходы для переходов состояний на одном промисе.
2) У нас есть handleCallback для передачи состояния между текущим обещанием и следующим обещанием.
3) У нас есть resolvePromise, специальная обработка для особого результата.
Далее нам просто нужно интегрировать и соединить части вместе.
Среди них конструктор Promise расширяется следующим образом:
Сконструируйте onFulfilled, чтобы переключиться в состояние выполнено, сконструируйте onRejected, чтобы переключиться в отклоненное состояние.
Создайте функции разрешения и отклонения, а в функции разрешения проверьте значение с помощью resolvePromise.
С флагом игнорирования гарантируется, что разрешение/отклонение вызывается только один раз.
Наконец, передайте разрешение/отклонение в качестве параметра функции f.
Если выполнение функции f сообщает об ошибке, эта ошибка используется как причина отклонения.
Функция перехода расширена, как указано выше, при изменении состояния все обратные вызовы очищаются асинхронно.
Мы реализовали handleCallback ранее, и для реализации handleCallbacks требуется только цикл.
После запуска набора тестов все прошло.
Реализована спецификация Promises/A+. (можно нажатьПосмотреть весь исходный код)
1.6, обещания ES2015
Спецификация Promises/A+ не совсем эквивалентна Promises ES2015. В спецификации A+ не описаны метод catch и статические методы, такие как Promsie.resolve, Promise.reject, Promise.all, Promise.race.
Даже использование нового промиса не входит в содержание спецификации A+, просто сейчас мы реализуем его в стиле промисов ES2015.
Промисы ES2015 совместимы со спецификацией Promises/A+ и имеют собственные расширения.
С помощью метода then мы можем легко реализовать несколько методов расширения для промисов ES2015.
Реализация метода catch и статических методов разрешения/отклонения показана выше. Реализация Promise.all и Promise.race оставлена заинтересованному читателю в качестве упражнения.
2. Разъяснить мифы
2.1. Если вы можете реализовать промисы вручную, вы должны быть опытными в промисах?
В компьютерной индустрии преобладает миф о наивном редукционизме. То есть, чем ближе к нижнему слою, тем выше техническое содержание. Каждый программист стремится понять базовый исходный код.
Это верно в определенной степени. Однако мы также должны видеть, что между нижним и поверхностным слоями существует доменный зазор. Быть опытным на дне не означает уровень на поверхности.
Например, разработчик игры не обязательно лучший в игре. Это особенно верно в отношении шутеров от первого лица или файтингов, где подавляющее большинство лучших игроков вообще не знают, как писать код.
Многообещающее мастерство определяется как умение использовать обещания для решения проблем в различных асинхронных сценариях.
Что ж, возможность писать реализации промисов вручную не сильно помогает в освоении промисов.
Спецификация Promise/A+, которая фокусируется на том, как реализовать.
вместо Как использовать.
Нереально надеяться раскрыть фантазию о боевых искусствах второй линии Рена и Ду, реализуя спецификации или так называемое понимание лежащего в основе исходного кода.
Если вы хотите освоить обещания, вам нужно больше думать и тренироваться в различных асинхронных сценариях ежедневной разработки.
Некоторым студентам должно быть любопытно, как объяснить, что многие разработчики, хорошо разбирающиеся в определенной технологии, действительно могут прочитать и реализовать спецификацию?
На самом деле, это типичный случай [принятия корреляции как причины и следствия].
Они не умеют читать и реализовывать спецификацию. Скорее, владение технологией вызывает у них интерес к чтению спецификации и ее реализации.
Редко видел, что там электрик пытается изучить электромагниты, и пойду на практикук электрика.Часто вижу, что фреймворк разработчика еще не наигрался, хочется разнести исходник фрейма.Код еще написан, я хочу смотреть норм языка.
Если вы хотите пропустить основательный процесс обучения и подготовки, переходите сразу к последнему шагу. Это похоже на попытку насытиться, съедая только последний кусочек еды.
2.2 Являются ли обещания более продвинутым асинхронным решением, чем обратные вызовы?
В Интернете множество статей описывают эволюцию асинхронных схем в JavaScript в следующем порядке:
callback -> promise -> generator -> async/await
Среди них callback считается худшим решением, а async/await — так называемым асинхронным окончательным решением.
С точки зрения модных тенденций это утверждение небезосновательно. Мы прошли шаг за шагом от стиля обратного вызова к сегодняшнему этапу асинхронности/ожидания.
Тем не менее, есть некоторые интересные вещи, о которых мы можем узнать.
2.2.1, обещания также являются типом стиля обратного вызова.
В первом абзаце спецификации Promises/A+ мы видим четкое утверждение:
Обещание заключается в регистрации обратных вызовов через метод then, где обратный вызов onFulfilled обрабатывает значение, а обратный вызов onRejected обрабатывает причину.
Стиль обратного вызова, который мы долгое время критиковали, обычно относится к обратным вызовам Error-First в nodejs или другим необработанным обратным вызовам.
обратный вызов сам по себе является очень широкой концепцией.
Следуя утверждению об управлении состоянием, мы можем понимать промисы как своего рода управление обратными вызовами.
И rxjs — это еще одно управление обратными вызовами.По сравнению с промисами, которые заботятся только о значении и причине одной асинхронной операции, rxjs может обрабатывать значения, ошибки и сигналы завершения нескольких асинхронных операций.
Если промисы могут обрабатывать 01 асинхронный результат, rxjs может обработать 0Infinite Бесконечное количество асинхронных результатов.
Очень разумное предположение: можем ли мы реализовать спецификацию Promises/A+ с помощью rxjs?
Кажется, что это не что иное, как сужение области обработки rxjs.
Ответ положительный.
Как и выше, мы можем инкапсулировать наблюдаемые данные rxjs в API в стиле обещаний и использовать слияние для внутреннего объединения значений.Для результата $ используйте механизм подписки rxjs для обработки обратных вызовов обещаний onFulfilled и onRejeted.
(нажмите чтобыПосмотреть репозиторий кода, для реализации Promises/A+ на основе rxjs).
Если мы думаем о обещаниях как о чем-то вроде управления обратными вызовами, то то, что мы думали раньше
Эволюция обратного вызова -> обещание становится процессом замены одного стиля обратного вызова другим.
2.2.2, функция-генератор также является стилем обратного вызова
Асинхронное решение, основанное на генераторе + обещание, может реализовать эффект написания асинхронного кода методом синхронной записи. Например, используя библиотеку co tj:
co(function* () {
var result = yield Promise.resolve(true);
return result;
}).then(function (value) {
console.log(value);
}, function (err) {
console.error(err.stack);
});
Такого рода магия исходит из функции обратного вызова функции-генератора.
Функцию-генератор можно рассматривать как интеграцию нескольких функций обратного вызова, которая возвращает объект-генератор, который содержит три метода: next, throw и return, где генератор.next(value) отправляет значение в функцию-генератор.
Этот процесс представляет собой процесс непрерывного использования нескольких функций обратного вызова, вырезанных ключевым словом yield.
Это может быть сложно понять с первого взгляда, мы можем рассмотреть простой случай.
Как показано на изображении выше, мы выводим 3 значения наружу через yield, получаем 3 значения извне, а затем возвращаем все собранные нами внешние входы.
Если мы удалим знак * и синтаксический сахар yield и представим его как наивную функцию, упрощенная форма будет следующей:
Как и выше, мы построили callback с 4 слоями вложенности, а затем в 4 вызовах следующей функции каждый слой раскручивался, и наконец слой callback очищался. Реализует поведение, аналогичное предыдущей функции генератора.
Наша обработка слишком упрощена. Создается только следующий метод, не предоставляются методы throw и return и не демонстрируется, как работать с yield в операторе цикла, но основная идея остается той же.
Мы можем думать о функциях-генераторах как о синтаксическом сахаре для выравнивания вложенных обратных вызовов с помощью ключевого слова yield.
Этот вид обработки не уникален для JavaScript.Еще более 20 лет назад, в 1990-х, Haskell использовал синтаксический сахар do-нотации, чтобы сгладить вложенный оператор связывания.
При компиляции с помощью babel функция генератора обессахаривается и выглядит следующим образом:
Вместо того, чтобы генерировать несколько вложенных обратных вызовов, он синтезирует функцию, разбивает ее на несколько частей с помощью вариантов переключения и выполняет один из вариантов за раз. Эквивалентно встраиванию нескольких обратных вызовов вместе.
Если функция генератора представляет собой управление обратным вызовом с синтаксическим сахаром, то эволюция асинхронного решения обещания -> генератора, о которой мы думали ранее, может быть понята как стиль обратного вызова с синтаксическим сахаром, заменяющим стиль обратного вызова вызываемого вручную метода then.
2.2.3 асинхронная функция также является обратным вызовом
Что касается эволюции генератора -> асинхронность/ожидание, то ее можно рассматривать как семантику и стандартизацию схемы обещание + генератор. В конце концов, знак * и ключевое слово yield не совсем точно отражают, что это асинхронная операция.
В процессе компиляции Babel результат компиляции async/await оборачивает слой функции asyncToGenerator на основе генератора.
Пока что мы можем преобразовать выражение эволюции асинхронных решений в JavaScript в следующий вид:
Raw Callback Style -> Promise Callback Style -> Generator Callback Style -> Async/Await Callback
они соответственно:
1) Стиль необработанного обратного вызова: наивная функция используется в качестве обратного вызова, принимая такие параметры, как ошибка, данные и т. д.
2) Стиль обратного вызова Promise: с помощью объекта {then} обрабатывайте две функции обратного вызова onFulfilled и onRejected.
- Стиль обратного вызова генератора: синтаксический сахар, который объединяет несколько вложенных обратных вызовов с помощью символа * и ключевого слова yield.
4) Стиль обратного вызова Async/Await: семантический и стандартизированный продукт стиля обратного вызова Promise + Generator с использованием ключевых слов async и await.
Новое утверждение в целом согласуется со старым утверждением. Он просто описывает эволюцию калибра от 4 разных вещей к эволюции разных форм одного и того же.
В дополнение к этому основному пути эволюции существуют и другие формы, такие как стиль обратного вызова RXJS.
Студенты, интересующиеся сущностью обратного вызова и лежащей в его основе концепцией, могут выполнить поиск по терминологии продолжения.
2.3 Является ли async/await лучшим асинхронным решением?
Я не совсем уверен, по какому измерению люди оценивают максимальное, когда говорят, что async/await — это идеальное асинхронное решение.
Если это относится к измерению выразительности, то есть несколько интересных фактов, которые мы можем понять.
2.3.1 Генераторная функция является более общей, чем асинхронная функция
Семантика и стандартизация не означают усиление способности, она может привести и к ослаблению способности.
async/await — это случай ограниченных возможностей.
Функция-генератор может поддерживать как синхронное, так и асинхронное поведение.
асинхронная функция поддерживает только асинхронное поведение.
Для библиотеки co tj обещание является только основным источником асинхронных данных, и co также может получать результаты из других источников асинхронных данных. Например, функции thunk.
Как показано выше, при получении функции thunk co передаст функцию обратного вызова в стиле nodejs.
Мы также можем поддерживать такие объекты, как наблюдаемые, которые дают rxjs, если нам нравится.
Это связано с тем, что co является библиотекой, она может максимально использовать все возможности функции генератора для достижения желаемой функции расширения.
Хотя async/await — это новый синтаксис, он должен основываться на стандартизации и иметь согласованную семантику. Это требует множества компромиссов, отказа от поддержки денормализованных объектов в обмен на четкую семантику.
Следовательно, async/await может получать результаты асинхронных данных только из объекта обещания, что является сокращением возможностей по сравнению с co.
2.3.2 Голые промисы более гибкие, чем async/await
Хотя в более чем 90% асинхронных сценариев async/await может быть эффективен, тем не менее, есть несколько сценариев, в которых написание промисов является более гибким.
Наиболее типичный случай — параллельная обработка промисов.
Как и выше, ключевое слово await всегда последовательное.Когда мы хотим получить a, b последовательно, это очень просто написать. Если мы хотим получить как a, так и b и дождаться их результата, с ключевым словом await сложно справиться.
Мы должны обернуть несколько обещаний в одно с помощью Promise.all самостоятельно.
Было предложение использовать await* в качестве синтаксического сахара для Promise.all. Однако он не приземлился.
Если хорошенько подумать, то легко понять, почему описанный выше метод сложно реализовать. Promise.all — это всего лишь одна из комбинаций промисов, есть еще комбинации Promise.race, Promise.allSettled и т.д.
Код было бы труднее читать, если бы каждой комбинации был назначен символ в качестве синтаксического сахара.
Итак, когда вам нужно объединить несколько промисов, написание промисов голыми является необходимой мерой.
Кроме того, async/await — это синтаксис, а не значение, поэтому его нельзя хранить и передавать. А объекты промисов, которые можно хранить в памяти, можно передавать в качестве параметров в функции.
Эта гибкость может принести удобство в некоторых особых сценариях. Например, мы можем кэшировать асинхронные результаты, кэшируя промисы.
Как показано выше, мы создаем карту, в которой хранится сопоставление URL -> обещание. Каждый раз, когда вы получаете URL-адрес, проверяйте кеш.
С синтаксисом Async / ждут, объекты обещания скрыты. Мы не можем получить это. После возврата результата отображение результата URL-> кэшируется.
Однако у этого подхода есть пробелы в покрытии кеша. Когда запрос на получение срабатывает, но результат еще не получен, срабатывает несколько одинаковых запросов, и эти запросы не могут попасть в кеш.
Если мы кэшируем объект обещания, то, используя функцию, позволяющую объекту обещания вызывать метод then несколько раз, мы можем сделать так, чтобы все URL-адреса получения получали один и тот же результат асинхронного запроса.
2.3.3 Голый обратный вызов более гибкий, чем обещание
Тогда Promise поддерживает только пути обратного вызова onFulfilled и onRejected, что является упрощением всех возможных путей обратного вызова.
Например, вышеупомянутые rxjs, наблюдатель и подписчик имеют {next, error, complete} три пути обратного вызова, которые могут обрабатывать больше случаев, чем обещание.
Если мы готовы управлять обратными вызовами вручную, теоретически мы можем быть более мощными и гибкими, чем промисы.
Например, режим callbag, предложенный автором cyclejs, реализует rxjs-подобные наблюдаемые и итерируемые объекты, используя только комбинацию нескольких функций обратного вызова.
A standard for JS callbacks that enables lightweight observables and iterables
Заинтересованные студенты могут перейти по ссылке выше, чтобы узнать о callbag.
Вдохновленный callbag, rxjs v7.0 подвергается внутреннему рефакторингу по аналогичной схеме. Они называют этот паттерн функциональными наблюдаемыми.
Заинтересованные студенты могут перейти по ссылке выше, чтобы узнать об идеях дизайна rxjs v7.0 (требуется преодоление стены).
Как и выше, мы видим, что async/await — самый слабый, а callback — самый сильный.
История развития асинхронных решений в JavaScript:
Raw Callback Style -> Promise Callback Style -> Generator Callback Style -> Async/Await Callback
Не процесс повышения выразительности, а процесс повышения удобства для разработчиков.
Стилю обратного вызова Rxjs было трудно стать массовым решением, потому что он не поддерживается синтаксическим сахаром и имеет много операторов, что, как известно, недружественно для новичков.
Стиль Callbag более антигуманный, и даже исходный код не способствует чтению. Подходит только для написания опытными разработчиками, скрыто внутри библиотеки/фреймворка.
2.3.4 Синтаксический сахар обходится дорого
На данный момент мы знаем, что синтаксис async/await можно рассматривать как синтаксический сахар для композиции нескольких функций обратного вызова, что может упростить сложность асинхронного кода, который мы пишем.
Однако это не без затрат.
Компилятор JS должен иметь дело с большим количеством сценариев, идентифицировать ключевые слова и точно обрабатывать разницу между асинхронной ошибкой броска и синхронной ошибкой броска. Заставьте async/await работать в гармонии с обычными функциями и работать в гармонии с функциями генератора.
Функция Async/await + генератор будет объединена в новую функцию асинхронного генератора, асинхронный генератор.
Как показано на рисунке выше, с помощью асинхронных генераторов + синтаксиса for-await мы можем одновременно получить возможности асинхронной обработки async/await и способность генераторов выводить несколько значений.
Существует библиотека axax, вдохновленная асинхронными генераторами для реализации схемы асинхронного потока данных, подобной rxjs. По сравнению с rxjs, который использует метод подписки для потребления данных, axax потребляет данные через синтаксис for-await.
Async Iterator Extensions for JavaScript e.g. map, reduce, filter, flatMap, etc.
Заинтересованные студенты могут щелкнуть ссылку выше, чтобы узнать об axax.
На сегодняшний день в JavaScript есть несколько типов функций:
-
простая функция
-
функция стрелки функция стрелки
-
генераторная функция генераторная функция
-
асинхронная функция асинхронная функция
-
асинхронная стрелочная функция асинхронная стрелочная функция
-
функция асинхронного генератора функция асинхронного генератора
Постоянно растущие типы функций и синтаксис создают большие проблемы для итерации и оптимизации компилятора, а также создают проблемы для новых функций языка ECMAScript. Итак, мы можем видеть асинхронную стрелочную функцию, но не стрелочную функцию генератора, а стрелочную функцию асинхронного генератора.
В будущем будет добавлено больше типов функций, и они будут упорядочены и объединены с предыдущими типами функций.Количество будет увеличиваться, и будет все труднее координировать несколько типов функций.
Это проблема, которой нельзя избежать при разработке языков программирования?
нет. Существуют и другие маршруты, такие функции, как async/await и итератор, могут отображаться в виде библиотеки вместо синтаксиса синтаксиса.
В приведенной выше статье описывается язык Koka с функциями алгебраических эффектов, который может эмулировать многие функции, включая async/await, с помощью обработчиков алгебраических эффектов, предоставляемых в виде библиотеки, а не синтаксиса языка. Не сильно увеличивает нагрузку на компилятор.
Предстоящая функция React Suspense, которая использует вышеуказанные возможности, внутренне имитирует алгебраические эффекты с помощью некоторых хаков в JS. Можно добиться того, что нет необходимости ждать асинхронной операции в функции рендеринга, и асинхронный результат может быть получен каким-то образом, не влияя на идемпотентные требования функции рендеринга.
Хотя алгебраические эффекты или Кока не были широко протестированы на практике, они дают нам представление о проблемах с текущими решениями и возможными решениями.
3. Резюме
В этом посте мы представляем пример реализации спецификации Promise/A+ менее чем в 100 строк кода и развеиваем несколько мифов о промисах и асинхронных решениях в JS.
Мы переделали представление истории эволюции асинхронных решений в JavaScript.
Мы также узнали, что async/await — это не окончательное асинхронное решение и не самый мощный режим для асинхронной обработки данных. Можно только сказать, что в настоящее время это основное решение, удобное для начинающих разработчиков.
Есть много других тем для обсуждения промисов, таких как их связь с функциональными монадами, например спорные и улучшающие части спецификации Promise/A+. Из-за нехватки места я остановлюсь здесь сегодня.