Промисы против наблюдаемых для миграции с AngularJS на Angular
AngularJS (Angular 1) активно использовал Promises для вызовов HTTP, в то время как Angular 2+ имеет сетевые вызовы, завернутые в Observables. Это привело к тому, что некоторые разработчики столкнулись с определенными проблемами при переносе проектов с AngularJS на Angular 2+. Я хочу рассмотреть эти проблемы здесь и описать, почему они вообще могут появляться, рассмотрев типичные различия между Observables и Promises..
Observables — больше возможностей для веб-разработчиков. (рис. медиамодификатор)
Pre-requisites: you should know JS Promises
Observables and Promises — краткое введение
На первый взгляд — Observables — это просто расширенные Promises: Promises выдает одно значение и завершается (разрешается), Observable выдает 0, одно или несколько значений и также завершается (выдача и завершение — это разные действия). Для HTTP-сервиса в AngularJS и Angular предоставляется только одно значение — поэтому кажется, что в этом случае оба фреймворка работают очень похоже.
И можно подумать, что достаточно просто переименовать $http к this.httpService , тогда к подписываться и все будут счастливы. В очень простых приложениях это даже может работать — но если ваше приложение делает что-то большее, чем «Hello world» — пожалуйста, обратите внимание на эти различия.
# 1 Нетерпеливый против ленивого
Взгляните на пример ниже:
Когда я звоню Сохранить изменения method — первый пример с запросом, обернутым в промис, будет работать как положено. Но в секундах Пример с Observable-оболочкой ничего не произойдет, потому что Observables ленивая оценка в то время как обещания нетерпеливо оцененный.
Это означает, что Promises не волнует, есть ли у них подписчики, чтобы получить результат или нет. А вот Observables (точнее — cold Observable) будут холодными, только если мы на них подпишемся. В приведенном выше случае вы должны подписаться на Observable, возвращаемый Сохранить изменения функция.
saveChanges(data).subscribe()
Чтобы следить за ним — используйте rxjs-не-игнорируемый-наблюдаемый правило от rxjs-tslint-правила по Николас Джеймисон.
#2 Promises нельзя отменить, а Observables можно отписать
Опять же, начнем с примера, когда при изменении входного текста мы выполняем поиск на бэкэнде:
В чем здесь недостаток — нельзя отклонить результаты предыдущего запроса, если пользователь продолжает печатать (debounce немного уменьшает эту проблему, но не устраняет ее). И еще одна проблема — возможно состояние гонки (когда более поздний результат запроса будет возвращаться быстрее, чем более ранний — поэтому мы получим некорректный ответ).
Observable может избежать этой проблемы довольно элегантно с переключательКарта оператор:
Здесь мы конвертируем вводимый текст в наблюдаемые выбросы значений. Каждый раз, когда выдается новое текстовое значение, оператор switchMap будет отменять предыдущий сетевой запрос (если он еще не завершен) и отправлять новый.
Packtpub.com и я подготовили целую RxJS курс со многими другими подробностями о том, как вы можете решать свои повседневные задачи разработчика с помощью этой удивительной библиотеки. Это может быть интересно для начинающих, но также содержит сложные темы. Взглянем!
# 3 Нет встроенной логики повтора или повтора для промисов. ‘повторение ‘ а также ‘повторить попытку ‘ операторы для Observables.
Вы можете реализовать логику повторных попыток с помощью промисов, но это выглядит немного громоздко:
В то время как тот же код Observables будет намного короче:
Подробнее о вариантах использования операторов повтора и повторной попытки см. моя статья.
#4 Небольшое количество комбинированных инструментов Promises. Для этого Observables предоставляют широкий спектр операторов.
Для Promises все возможности, которые вы можете комбинировать, следующие:
Обещание.все— ожидание разрешения всех промисов, а затем предоставление массива результатов.
Обещание.гонка— дождитесь, пока одно из промисов будет разрешено, и верните этот результат.
Observables дают очень богатые боеприпасы для создания комбинаций:
объединитьПоследние(наблюдаемый1, наблюдаемый2,…)— ждет, пока любой из наблюдаемых испустит и предоставит массив последних испущенных значений из всех наблюдаемых (результат: [value_obs1, value_obs2,..]). Очень хорошо, если вам нужно обновить страницу новыми данными из нескольких разных источников.
**observable1.pipe(withLatestFrom(observable2) **— для каждого значения из observable1 также укажите последнее выданное значение для observable2 (результат: [value_obs1, value_obs2]).
forkJoin(наблюдаемый1, наблюдаемый2,…) — аналог Promise.all — ждет, пока все Observables будут завершены, а затем выдает массив последних значений из всех наблюдаемых аргументов.
молния (наблюдаемый1, наблюдаемый2,…)— ждет, пока все наблюдаемые аргументы выдадут значения с одним и тем же индексом и предоставят массив выданных значений с одним и тем же индексом (результат: [value_obs1, value_obs2,..]).
**race(observable1, observable2,…) — **возвращает Observable, который отражает первый исходный Observable для испускания элемента.
**merge(observable1, observable2,…) — **подписывается на каждый наблюдаемый аргумент и повторно выдает значения из всех них.
переключатьВсе— если предыдущий Observable не завершен — отменить его и подписаться на новый.
конкат (наблюдаемый1, наблюдаемый2,…)— запускать следующую последовательность Observable только после завершения предыдущей (выдает значения одно за другим после каждого конкретного завершения Observable)
И многое другое(переключательКарта, раздел, если, группа по, окнотак далее)
Вы можете узнать больше об этих операторах здесь:
- Научитесь комбинировать последовательности RxJs с интуитивно понятными интерактивными диаграммами.
- Официальные документы с примерами
- «Практический RxJS для веб-разработки» видеокурс.
# 5 Легко предотвратить состояние гонки с помощью Observable и сложно — с Promises.
Скажем, мы периодически делаем сетевой запрос обновленных данных. Но в некоторых ситуациях более поздний результат запроса возвращается быстрее, чем более ранний — поэтому мы получаем некорректный (более ранний) ответ, отображаемый как последний.
На этот код может повлиять проблема состояния гонки.
Чтобы предотвратить это с помощью запросов, обернутых в Observable, мы можем использовать concatMap оператор.
concatMapсделает следующий сетевой вызов только после того, как предыдущий будет сделан и обработан. Конечно, если вам не нужны предыдущие результаты — тогда используйте switchMap (как в первом примере этой статьи).
Вывод
Во время миграции с AngularJS (использует промисы для сетевых вызовов) на Angular 2+ (использует Observable) вы должны знать о возможных различиях промисов и Observable. Надеюсь, моя статья помогла вам прояснить эту тему. Теперь пришло время мигрировать!
Нравится эта статья? Будем на связи Твиттер.
Этот пост изначально был опубликован в ИТНЕКСТ.
Начиная с раздела 4 моего Видеокурс RxJS авансы персонала проверены — так что, если вы уже знакомы с RxJS — вы также можете найти что-то полезное для себя: наблюдаемые объекты более высокого порядка, антипаттерны, планировщики, модульное тестирование и т. д.! Попробуйте !