В чем разница между Обещаниями и Наблюдателями?

angular promise rxjs angular-promise angular-observable


В чем разница между Promise и Observable в Angular?

Пример по каждому из них был бы полезен для понимания обоих случаев.В каком сценарии мы можем использовать каждый случай?




Answer 1 Günter Zöchbauer


Promise

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

Примечание. Существуют библиотеки Promise , которые поддерживают отмену, но ES6 Promise пока нет.

Observable

Observable подобен Stream (на многих языках) и позволяет передать ноль или больше событий , когда функция вызывается для каждого события.

Часто Observable предпочтительнее Promise , потому что он предоставляет функции Promise и многое другое. С Observable не имеет значения, хотите ли вы обрабатывать 0, 1 или несколько событий. Вы можете использовать один и тот же API в каждом случае.

Observable также имеет преимущество перед Promise для отмены . Если результат запроса HTTP на сервер или какой - либо другой операции дорогой асинхронном больше не требуется, то Subscription на Observable позволяет отменить подписку, в то время как Promise , в конечном счете вызвать успех или сбой обратного вызова , даже если вы этого не сделаете Нужно уведомление или результат, который он предоставляет больше.

Наблюдаемое предоставляет операторам как map , forEach , reduce , ... похож на массив

Существуют также мощные операторы, такие как retry() или replay() , ... которые часто очень удобны.




Answer 2 trungk18


И Promises , и Observables предоставляют нам абстракции, которые помогают нам справляться с асинхронной природой наших приложений. Разница между ними была четко указана @ Günter и @Relu.

Поскольку фрагмент кода стоит тысячи слов,давайте рассмотрим пример ниже,чтобы легче его понять.

Спасибо @Christoph Burgdorf за отличную статью


Угловой использует Rx.js Observables вместо обещаний для работы с HTTP.

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

  • Мы не хотим попадать на конечную точку сервера каждый раз, когда пользователь нажимает клавишу, он должен заполнять их потоком HTTP - запросов. По сути, мы хотим нажать на него только после того, как пользователь перестал печатать вместо каждого нажатия клавиши.
  • Не нажимайте конечную точку поиска с теми же параметрами запроса для последующих запросов.
  • Разберитесь с неупорядоченными ответами. Когда у нас есть несколько запросов одновременно, мы должны учитывать случаи, когда они возвращаются в неожиданном порядке. Представьте, что мы сначала печатаем компьютер , останавливаемся, запрос отправляется, мы набираем машину , останавливаем запрос отправляем. Теперь у нас есть два запроса в полете. К сожалению, запрос, содержащий результаты для компьютера, возвращается после запроса, который содержит результаты для автомобиля .

Демо будет просто состоять из двух файлов: app.ts и wikipedia-service.ts . В сценарии реального мира мы, скорее всего, разделим вещи дальше.


Ниже приведена реализация на основе Promise , которая не обрабатывает ни один из описанных крайних случаев.

wikipedia-service.ts

import { Injectable } from '@angular/core';
import { URLSearchParams, Jsonp } from '@angular/http';

@Injectable()
export class WikipediaService {
  constructor(private jsonp: Jsonp) {}

  search (term: string) {
    var search = new URLSearchParams()
    search.set('action', 'opensearch');
    search.set('search', term);
    search.set('format', 'json');
    return this.jsonp
                .get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', { search })
                .toPromise()
                .then((response) => response.json()[1]);
  }
}

Мы Jsonp сервис Jsonp для выполнения запроса GET к API Википедии с заданным поисковым термином. Обратите внимание, что мы вызываем toPromise , чтобы перейти от Observable<Response> к Promise<Response> . В конечном итоге Promise<Array<string>> в качестве возвращаемого типа нашего метода поиска.

app.ts

// check the plnkr for the full list of imports
import {...} from '...';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Wikipedia Search</h2>
      <input #term type="text" (keyup)="search(term.value)">
      <ul>
        <li *ngFor="let item of items">{{item}}</li>
      </ul>
    </div>
  `
})
export class AppComponent {
  items: Array<string>;

  constructor(private wikipediaService: WikipediaService) {}

  search(term) {
    this.wikipediaService.search(term)
                         .then(items => this.items = items);
  }
}

Здесь тоже нет ничего удивительного. Мы внедряем наш сервис WikipediaService и раскрываем его функциональность с помощью метода поиска в шаблоне. Шаблон просто привязывается к keyup и вызывает search(term.value) .

Мы разворачиваем результат Обещания, который возвращает метод поиска WikipediaService, и выставляем его в виде простого массива строк в шаблон, чтобы мы могли через него *ngFor цикл * ngFor и создать для нас список.

Посмотрите пример реализации на основе Promise на Plunker


Где наблюдаемые действительно сияют

Давайте изменим наш код, чтобы не забивать конечную точку при каждом нажатии клавиши, а вместо этого отправлять запрос только тогда, когда пользователь перестал печатать в течение 400 мс

Чтобы раскрыть такие сверхспособности, нам сначала нужно получить Observable<string> которая содержит поисковый термин, который вводит пользователь. Вместо ручной привязки к событию formControl мы можем воспользоваться преимуществом директивы Angular formControl . Чтобы использовать эту директиву, нам сначала нужно импортировать ReactiveFormsModule в наш модуль приложения.

app.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { JsonpModule } from '@angular/http';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [BrowserModule, JsonpModule, ReactiveFormsModule]
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

После импорта мы можем использовать formControl из нашего шаблона и установить его в название "термин".

<input type="text" [formControl]="term"/>

В нашем компоненте мы создаем экземпляр FormControl из @angular/form и выставляем его как поле под термином имени в нашем компоненте.

За кулисами термин автоматически выставляет Observable<string> как свойство valueChanges ,на которое мы можем подписаться. Теперь, когда у нас есть Observable<string> , преодолеть пользовательский ввод так же просто, как вызвать debounceTime(400) для нашего Observable . Это вернет новый Observable<string> который будет выдавать новое значение, только если новые значения не поступали в течение 400 мс.

export class App {
  items: Array<string>;
  term = new FormControl();
  constructor(private wikipediaService: WikipediaService) {
    this.term.valueChanges
              .debounceTime(400)        // wait for 400ms pause in events
              .distinctUntilChanged()   // ignore if next search term is same as previous
              .subscribe(term => this.wikipediaService.search(term).then(items => this.items = items));
  }
}

Было бы напрасной тратой ресурсов на отправку еще одного запроса по поисковому запросу, для которого наше приложение уже показывает результаты. Все , что нам нужно сделать , чтобы добиться желаемого поведения, чтобы вызвать distinctUntilChanged право оператора после того, как мы назвали debounceTime(400)

Смотрите пример реализации Observable на Plunker

Чтобы разобраться с неупорядоченными ответами, ознакомьтесь с полной статьей http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html.

Поскольку я использую Http в Angular,я согласен,что в нормальных случаях использования нет большой разницы при использовании "Наблюдаемый" над "Обещанием".Ни одно из преимуществ на практике не имеет здесь никакого значения.Надеюсь,что в будущем я смогу увидеть какой-нибудь продвинутый вариант использования :).


Узнать больше




Answer 3 Alireza


И Promises, и Observables помогут нам работать с асинхронными функциями в JavaScript. Во многих случаях они очень похожи, однако между ними все еще есть некоторые различия, обещания - это значения, которые разрешаются asynchronous способами, такими как вызовы http . С другой стороны, наблюдаемые имеют дело с последовательностью асинхронных событий . Основные различия между ними перечислены ниже:

promise:

  • имея один трубопровод
  • обычно используется только с асинхронным возвратом данных
  • непростая отмена

observable:

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

Кроме того,я создал для вас графическое изображение ниже,чтобы показать различия визуально:

Promises and Observables image




Answer 4 Aravind


Promises

  1. Определение: помогает выполнять функции асинхронно и использовать их возвращаемые значения (или исключения), но только один раз при выполнении.
  2. Не ленивый
  3. Не отменяется(Есть библиотеки Promise,которые поддерживают отмену,но ES6 Promise пока не отменяется).Два возможных решения
    • Reject
    • Resolve
  4. Невозможно повторить (Promises должен иметь доступ к исходной функции, которая вернула обещание с возможностью повторной попытки, что является плохой практикой)

Observables

  1. Определение: Помогает вам выполнять функции асинхронно и использовать их возвращаемые значения в непрерывной последовательности ( несколько раз ) при выполнении.
  2. По умолчанию,это Ленивый,так как он излучает значения,когда время прогрессирует.
  3. Имеет множество операторов,что упрощает процесс кодирования.
  4. Один оператор повторной попытки может быть использован для повторной попытки, когда это необходимо, также, если нам нужно повторить наблюдаемое на основе некоторых условий, повторная попытка при использовании.

    Примечание : список операторов вместе с их интерактивными диаграммами доступен здесь на RxMarbles.com




Answer 5 besserwisser


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

async function getData(){
    const data = await observable.first().toPromise();
    //do stuff with 'data' (no callback function needed)
}

Дальнейшее чтение: Как я могу «ждать» на Rx Observable?