Сравнение ключевых характеристик Observables и Promises

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

Как мы можем полагаться на результаты асинхронных функций? На ранних стадиях обратные вызовы были единственным доступным подходом. Однако они сделали код трудным для чтения, что привело к известному аду обратных вызовов.

Observables и Promises были созданы, чтобы точно решить эту проблему. Их реализации помогают нам работать с этим асинхронным кодом более чистым способом. У них разные API, и их мотивация немного другая.

Как узнать, какой из них нам подходит? Здесь мы увидим разницу между каждой реализацией. Это поможет нам выбрать правильный инструмент для правильной работы.

Основные отличия

Как упоминалось ранее, у Promises и Observables совершенно другой подход к работе с асинхронным кодом. Здесь мы проверим четыре основных отличия.

Чтобы следовать примерам, вы можете использовать веб-консоль браузера rxjs web dev.

1. Одно значение или несколько значений

Самая большая разница в том, что обещания не меняют своего значения после того, как они были выполнены. Они могут выдавать (отклонять, разрешать) только одно значение. С другой стороны, наблюдаемые могут выдавать несколько результатов. Подписчик будет получать результаты до тех пор, пока наблюдатель не заполнится или не откажется от подписки. Вот код, чтобы показать вам эти различия:

Это делает Observables отличным инструментом для прослушивания потоков данных. Существует даже двунаправленный тип Observable: Subjects. Идеальный вариант использования для них - web sockets. Библиотека RxJS поставляется с тонкой оболочкой для веб-сокетов.

import { webSocket } from "rxjs/webSocket";

2. Наблюдаемые подписки можно отменить; обещания не

Как только вы начнете обещание, вы не сможете его отменить. callback, переданный конструктору Promise, будет отвечать за разрешение или отклонение обещания. Абонент пассивен; однажды выстрелив, он может просто отреагировать на результат.

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

Есть много способов аннулировать / завершить подписку. Давайте проверим три самых распространенных:

  • unsubscribe: ручная отмена подписки из Observable
  • take: оператор для взятия числа X элементов и отмены подписки
  • takeUntil: оператор, который продолжает принимать значения, пока переданный Observable не выдаст какое-либо значение.

Давайте посмотрим на примеры для каждого из вышеперечисленных:

Операторы Observable очень важны. Они позволяют нам составлять декларативно сложные асинхронные операции. В приведенном выше примере ясно, насколько важны и удобочитаемы операторы take и takeUntil.

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

Давайте посмотрим на представление оператора take:

У нас есть представление input и output потоков операторов.

3. Жадное и ленивое исполнение

Есть разница в том, как выполняются Observables и Promises. Обещания выполняются нетерпеливо, в то время как Observables выполняются лениво. Что это обозначает?

Eagar: обратный вызов Promise будет выполнен сразу на уровне конструктора.

Ленивый: функция производителя сработает только после создания подписки для этого наблюдаемого объекта. В противном случае он будет бездействовать.

Давайте посмотрим на примеры для обоих:

В приведенном выше примере мы можем увидеть, как записанные в журнал операторы 1. Callback execution и 1. Execution of observable body выполняются в другом порядке.

4. Выполнение во время выполнения

После выполнения обещания ES помещают обратный вызов в очередь микрозадач. Это означает, что они будут выполнены после завершения текущей макро-задачи.

Давайте посмотрим на пример:

Вы не можете изменить вышеуказанное поведение.

С помощью Observables вы можете точно настроить выполнение во время выполнения с помощью планировщиков. Планировщик контролирует, когда начинается подписка и когда доставляются уведомления.

  • null: по умолчанию уведомления доставляются синхронно и рекурсивно.
  • queueScheduler: расписания в очереди в текущем кадре события.
  • asapScheduler: расписания в очереди микрозадач. Та же очередь, что и promises.
  • asyncScheduler: аналогично планированию задачи с использованием setInterval. Поэтому он будет запланирован в очереди задач макроса.
  • animationFrameScheduler: полагается на requestAnimationFrame API.

Давайте посмотрим на пример с asapScheduler:

Совместимость

Могут ли они работать вместе, учитывая, что между ними довольно много различий? Придется ли нам выбирать между одним из них? Точно нет.

Вы можете создавать Observable из обещаний, а можете выгружать Observable в Promise. Однако в последнем случае, поскольку промисы принимают только одно значение, вам нужно будет выбрать, хотите ли вы, чтобы первое или последнее значение сбрасывалось в промис. Библиотека rxjs предоставляет firstValueFrom и lastValueFrom для этого конкретного варианта использования.

Давайте посмотрим на несколько примеров:

Последние мысли

Мы видели различия между ними. Когда использовать тот или иной вариант - это вопрос предпочтений и варианта использования. Оба отлично подходят для решения асинхронной парадигмы в JavaScript.

Имейте в виду, что Observables имеют свою цену. Они изначально не поддерживаются браузером. Реализация библиотеки для перехода - RxJS. Размер пакета может достигать 17.4kb. Поскольку это дерево дрожащее, вы наверняка будете смотреть на меньшее. Это небольшой пакет, но обещания поддерживаются изначально. Это означает, что вы сэкономите на наблюдаемом налоге на пакет.

Ваше здоровье.

Не являетесь участником среднего уровня? Поддержи меня здесь, став им.

Связанный