Яка різниця між Обіцянками та Спостережними?


1395

Яка різниця між кутовими Promiseта Observableв них?

Приклад кожного з них буде корисним для розуміння обох випадків. У якому сценарії ми можемо використовувати кожен випадок?


23
Я б запропонував вам прочитати цю публікацію; Angular2 обіцяють проти спостережуваного
erolkaya84


3
Кожен, хто читає це питання і відповіді - як хтось, хто бере участь у обох світах від сервісного сервісу, спікера та довгострокового користувача, я рекомендую вам прочитати офіційні документи RxJS та документацію MDN про обіцянки. Я особисто вважаю відповіді тут цілком оманливими та невірними, і вважаю, що вони є, хоча з добрими намірами людей, які намагаються допомогти, дуже шкідливі.
Бенджамін Грюенбаум

1
Я б запропонував вам прочитати цей кутовий офіційний документ angular.io/guide/comparing-observables
fgul

І саме тому посилання вважаються неприйнятними як відповіді.
Дейв

Відповіді:


1547

Обіцяють

Ручка Promiseобробляє одну подію, коли операція асинхронізації завершена або завершена.

Примітка: Існують Promiseбібліотеки, які підтримують скасування, але ES6 Promiseпоки не працює.

Спостерігається

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

Часто Observableвіддається перевагу над Promiseтим, що він забезпечує особливості Promiseта багато іншого. З Observableцим не має значення, чи потрібно обробляти 0, 1 або кілька подій. Ви можете використовувати один і той же API в кожному випадку.

Observableтакож має перевагу перед Promiseбути анульовані . Якщо результат запиту HTTP на сервер чи інша дорога операція з асинхронізацією більше не потрібен, Subscriptionпрограма Observableдозволяє скасувати підписку, в той час як a Promiseв кінцевому підсумку буде викликати успішний або невдалий зворотний дзвінок, навіть коли вам не потрібно повідомлення або результат, який він надає більше.

Спостережуване надає операторам , як map, forEach, reduce, ... схожі на масив

Також є потужні оператори, такі як retry(), або replay(), ..., які часто дуже зручні.


180
Тож чи є вагомі підстави використовувати Promise замість Observable у випадку єдиного зворотного виклику чи слід також використовувати Observables там, оскільки вони також можуть працювати таким чином? По суті, чи є хорошою практикою «спостерігати за всіма речами» чи «Обіцянка» все ще має своє місце?
Джош Вертс

75
Якщо ви хочете використовувати реактивний стиль, просто використовуйте спостереження скрізь. Якщо у вас є лише спостереження, ви можете легко скласти. Якщо їх змішати, то вже не так чисто. Якщо ви не переймаєтесь реактивним стилем, ви можете використовувати обіцянки для одиночних подій, де ви не переймаєтесь відміною та спостереженням за потоками подій.
Günter Zöchbauer

35
@ GünterZöchbauer Гей - у мене немає аргументів проти спостережуваних або функціонального програмування. Я просто констатую, що я вважаю, що люди, які впадають у Спостереження переважно через http в NG2, не мають жодної реальної причини використовувати спостереження за обіцянками для здійснення дзвінків. Вони не втрачають нічого практичного, використовуючи обіцянки. Оператори дебютування та повторних операцій не мають значення - ви можете дебютувати за допомогою ng-debounce, і якщо очікується, що дзвінок не вдасться, як правило, проблема з кодом є. Єдиний час, коли мені потрібно було працювати з повторними повторними дзвінками, було запитувати нестабільні сторонні API для HVT.
VSO

92
Але, не забувайте, що Promiseразом із async/ знову awaitробить ваш код рівним! У більшості ситуацій, і в проектах, які не займаються ракетною наукою, немає необхідності писати ті жахливі вкладені функції з надмірно складними ланцюжками методів. Ви можете користуватися async/ awaitсьогодні з транспіляторами, як-от TypeScript, і писати фактичний читаний людиною плоский код без жодної панелі rxjsкотла. Напевно, вам все одно знадобиться rxjsіноді у вибраних ситуаціях, адже це дійсно є багато чого запропонувати.
evilkos

15
Ця відповідь вводить в оману, спостерігається не як потік, це як функція, яка повертає потік .
Бенджамін Груенбаум

333

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

Оскільки фрагмент коду коштує тисячу слів, перегляньте наведений нижче приклад, щоб зрозуміти їх легше.

Дякуємо @Christoph Burgdorf за приголомшливу статтю


Angular використовує Rx.js Спостереження замість обіцянок для роботи з HTTP.

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

  • Ми не хочемо потрапляти на кінцеву точку сервера щоразу, коли користувач натискає клавішу, це повинно залити їх бурею HTTPзапитів. В основному, ми хочемо вдарити його лише після того, як користувач перестане друкувати, а не кожен натискання клавіші.
  • Не вдаряйте кінцеву точку пошуку тими ж парами запитів для наступних запитів.
  • Попрацюйте з відповідями, що не були в порядку. Коли у нас є кілька запитів під час польоту одночасно, ми повинні враховувати випадки, коли вони повертаються в несподіваному порядку. Уявіть, ми спочатку набираємо комп’ютер , зупиняємося, запит виходить, ми набираємо машину , зупиняємося, запит виходить. Зараз у нас є два запити в польоті. На жаль, запит, який містить результати для комп'ютера, повертається після запиту, який містить результати для автомобіля .

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


Нижче наведено реалізацію на основі обіцянок , яка не обробляє жоден із описаних крайових випадків.

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сервісу зробити 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і виставляємо її функціональність за допомогою методу пошуку до шаблону. Шаблон просто пов'язується з клавіатурою та дзвінками search(term.value).

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

Дивіться приклад Promise на основі реалізації на Plunker


Де спостереження дійсно сяють

Давайте змінимо наш код, щоб не забивати кінцеву точку при кожному натисканні клавіші, а натомість надсилатимемо запит лише тоді, коли користувач перестав друкувати на 400 мс.

Щоб розкрити такі суперпотужності, спочатку нам потрібно отримати знак, Observable<string>який містить пошуковий термін, який вводить користувач. Замість того, щоб вручну прив’язуватися до події клавіатури, ми можемо скористатись formControlдирективою Angular . Щоб використовувати цю директиву, спочатку нам потрібно імпортувати 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)

Дивіться приклад спостережуваної реалізації на Plunker

Для розгляду відповідей, що не відповідають порядку, перегляньте повну статтю http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

Наскільки я використовую Http в Angular, я погоджуюся, що у звичайних випадках використання немає великої різниці при використанні Observable over Promise. Жодна з переваг тут насправді не актуальна на практиці. Сподіваюся, я можу побачити певний випадок розширеного використання в майбутньому :)


Вивчайте більше


31
Я не повністю купую рішення перетворити послугу Http в систему, що базується на спостереженні. Кожне пояснення, яке я чую, спирається на той самий приклад: Пошук за терміном. Але це стосується обробки подій браузера. Я хотів би почути, яка перевага полягає в застосуванні його під час роботи з асинхронними запитами http.
Алекс Поллан

1
Чи було рішення випадковим уникнути змішаних зразків?
Алекс Поллан

6
@AlexPollan, насправді є хорошим поясненням переваг сервісу http, який повертає спостережливе в цьому подкасті з Беном Лешем: devchat.tv/js-jabber/… . Зрештою, головна перевага полягає в тому, що ви можете скасувати спостережуваний, і випадок використання для цього, описаний у посиланні вище - при цьому трохи надуманий - полягає в тому, що якщо ви звертаєтесь до декількох апсісів і дбаєте лише про першу відповідь, незалежно від того звернувся до вас apis повертається спочатку, ви можете скасувати запити в інших.
nikolasleblanc

2
@nikolasleblanc, я впевнений, що ви можете використовувати для цього $ q.race ()?
jameslouiz

2
@AlexPollan, Перевага полягає в тому, що сервіс HTTP на основі спостереження полегшує скасування HTTP-запитів середнього польоту. Умови перегонів у відповіді trungk18 можна вирішити, просто відписавшись від HTTP, що спостерігається, перш ніж подавати наступний запит. RXJS switchMap можна використовувати для HTTP-запитів, викликаних іншим спостережуваним (наприклад, valueChanges). Для автономних HTTP-спостережень ви можете скасувати передплату та повторну підписку вручну.
Stevethemacguy

234

І обіцянки, і спостереження допоможуть нам працювати з асинхронними функціоналами в JavaScript. Вони дуже схожі у багатьох випадках, проте, між ними все ще є деякі відмінності, обіцянки - це значення, які вирішаться asynchronousтаким чином, як http- дзвінки. З іншого боку, спостерігачі мають справу з послідовністю асинхронних подій . Основні відмінності між ними наведені нижче:

обіцянка:

  • маючи один трубопровід
  • зазвичай використовують лише для повернення даних асинхронізації
  • скасувати непросто

помітний:

  • можна скасувати
  • повторно спрацьовуються за своєю природою, такі як повтор і повтор
  • передавати дані в декілька конвеєрів
  • з операціями, що нагадують масив, як карта, фільтр тощо
  • можна створити з інших джерел, таких як події
  • це функції, на які можна було підписатись згодом

Також я створив для вас графічне зображення нижче, щоб наочно показати відмінності:

Обіцянки та спостереження образу


4
обіцяють "не просто скасувати", чи можна їх скасувати?
Pardeep Jain

10
так, є спосіб скасувати їх також ... деякі користуються бібліотеками bluebird або сторонніми бібліотеками ... також використовуючи Q-бібліотеку у Angular, є способи її скасувати ... але, як я вже сказав, не дуже зручно
Alireza

Наявність одного трубопроводу іноді має переваги, напр. в APP_INITIALIZER, якщо у вас є кілька трубопроводів, він ніколи не може закінчуватися інколи або закінчуватися кілька разів.
windmaomao

6
скасування а Promise- неправильний спосіб думати про те, як обіцяє. Ви Promiseнесете відповідальність лише за обробку успіху чи провалу сумісним чином з асинхрією. Якщо ви хочете скасувати запит http, ви скасуєте запит, а не обіцянку, і в результаті скасування або виконаєте Обіцяння. jsfiddle.net/greggman/ea0yhd4p
gman

2
@gman Рівно. Обіцянка просто представляє якусь майбутню цінність . Він не представляє операцію, яка генерує значення . Ви не можете скасувати значення. Ви не можете повторити значення. Це просто цінність. Він може бути або ще не присутній , і він ніколи не може існувати, оскільки стався виняток, але це все.
Йона Апплетре

75

Обіцянки

  1. Визначення: допомагає запускати функції асинхронно та використовувати їх повернені значення (або винятки), але лише один раз при їх виконанні.
  2. Не лінивий
  3. Не можна скасувати (там є бібліотеки Promise, які підтримують скасування, але ES6 Promise поки що не діє). Можливі два рішення
    • Відхилити
    • Вирішіть
  4. Не може бути повторений (Обіцянки повинні мати доступ до вихідної функції, що повертає обіцянці мати можливість повторного запуску, який є поганою практикою)

Спостережні

  1. Визначення: допомагає запускати функції асинхронно та використовувати їх повернені значення у безперервній послідовності ( кілька разів ) при їх виконанні.
  2. За замовчуванням це Ледачий, оскільки він випускає значення, коли час прогресує.
  3. Має багато операторів, що спрощує кодування.
  4. Один оператор повтор може бути використаний , щоб повторити спробу , коли це необхідно, а також , якщо необхідно повторити спостерігаються на основі деяких умов retryWhen можуть бути використані.

    Примітка : Список операторів разом з їх інтерактивними діаграмами доступний тут на RxMarbles.com


67

У відповідях є один недолік спостережень. Обіцяння дозволяють використовувати функції асинхронізації / очікування ES7. За допомогою них ви можете писати асинхронний код так, як це був би синхронний виклик функції, тому вам більше не потрібні зворотні дзвінки. Єдиною можливістю для спостерігачів це зробити - це перетворити їх на Обіцяння. Але перетворюючи їх у Обіцяння, ви можете знову мати лише одне повернене значення:

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

Подальше читання: Як я можу "чекати" на Rx-спостережуваному?


21
Також здивовано, чому ніхто не вказував на цей вбивчий завиток Обіцянь - простота та прозорість завдяки асинхронності / очікуванню. Я перейшов на «Обіцянки» лише для вміння писати плоский код. Проста бізнес-логіка та код взаємодії з інтерфейсом користувача не повинні виглядати як ракетна наука та бути забрудненими вкладеним пекельним реактивним розширенням. Крім того, асинхронізація / очікування не тільки в майбутньому, ви можете використовувати його в додатках загальнодоступного виробництва зараз, використовуючи транспілери. Я використовую TypeScript 2.3, і це приголомшливо, як реальна мова.
evilkos

Приємно, але реагуючи на реактивний спосіб і все з RxOperators, можливо, це не вбивча особливість
JorgeTovar

37

Обіцянки та спостереження обробляють лише асинхронний виклик.

Ось відмінності між ними:

Спостерігається

  1. Випускає кілька значень протягом певного періоду часу
  2. Не називається, поки ми не підписалися на спостережуване
  3. Можна скасувати за допомогою методу unsubscribe ()
  4. Надає карту, forEach, фільтрує, зменшує, повторює і повторює оператори

Обіцяють

  1. Одночасно випускає лише одне значення

  2. Дзвінки на послуги без .then та .catch

  3. Не можна скасувати

  4. Не надає жодних операторів


2
Що саме ви маєте на увазі під обіцянкою, випромінює лише одне значення, а спостережуване
Abel

2
Обіцянка взагалі не випромінює значення - обіцянка - це значення з часом. Багатообіцяючі обіцянки, які мають значення для декількох підписників - як тільки ви виконаєте обіцянку, у вас вже є цінність. Спостережуване - це як функція , підписка на нього викликає дію.
Бенджамін Грюнбаум

1
@BenjaminGruenbaum Тим не менш, я не отримав середнього значення декількох підписників, будь ласка, будь ласка, наведіть посилання або приклад. Спасибі
Діпак Пацідар

2
observable1.subscribe (передплатник1), observable1.subscribe (Subscri22) - це функція викликає кілька разів.
Бенджамін Груенбаум

2
Будь ласка , змініть свій пост і показати фактичний текст замість скріншотів. Інші не можуть копіювати та вставляти з ваших зображень, а також не можуть допомогти виправити багато граматичних помилок. Детальніше дивіться тут . Дякую.
Панг

25

Незважаючи на те, що ця відповідь запізнюється, я підсумував різниці нижче,

Спостерігається:

  1. Спостережуване - це лише functionте, що приймає an observerта повертає a function Observer: an object with next, error.
  2. Спостерігач дозволяє subscribe/unsubscribeсвоєму потоку даних видавати наступне значення спостерігачеві, notifyспостерігачеві про errorsта інформувати спостерігача проstream completion
  3. Спостерігач забезпечує function to handle next value, помилки та кінець потоку (події ui, відповіді http, дані з веб-сокетами).
  4. Працює з multiple valuesчасом
  5. Це cancel-able/retry-ableі підтримує операторів, таких як map,filter,reduceі т.д.
  6. Створення спостережуваного може бути - Observable.create()- повертає спостережуване, що може викликати методи на - Observer Observable.from()- перетворює масив або ітерабельний в - Observable Observable.fromEvent()- перетворює подію в спостережуване - Observable.fromPromise()- перетворює обіцянку в спостережуване - Observable.range()- повертає послідовність цілих чисел у вказаному діапазоні

Обіцянка :

  1. Обіцянка являє собою завдання, яке завершиться в майбутньому;

  2. Обіцянки стають resolved by a value;

  3. Обіцянки відхиляються винятками;

  4. Ні, cancellableі вона повертаєтьсяa single value

  5. Обіцянка відкриває функцію (then)

    -нато повертає нове promise;

    -дозволи на те, attachmentщо буде виконано на основі state;

    - handlersпідлягають guaranteedвиконанню order attached;


20

Я щойно розглядав питання, де обіцянки були найкращим рішенням, і я ділюсь цим тут для тих, хто натрапляє на це питання у випадку, якщо це корисно (саме такий відповідь я шукав раніше):

У проекті Angular2 у мене є служба, яка приймає деякі параметри і повертає список значень для заповнення випадаючих меню форми. Коли компонент форми ініціалізується, мені потрібно викликати одну і ту ж службу кілька разів з різними параметрами, щоб визначити кількість різних спадних меню, однак, якщо я просто встановити в чергу всі змінні, щоб викликати службу, тільки остання успішна, а решта помилка з. Отримання служби з бази даних може обробляти лише один запит за один раз.

Єдиним способом успішного заповнення всіх змінних меню, що випадає, було викликати службу таким чином, щоб запобігти обробці нового запиту до останнього запиту, а механізм Обіцяння /. Потім вирішив проблему непогано.

  fetchValueList(listCode): Promise<any> {
      return this.dataSvc.getValueList(listCode, this.stateSvc.currentContext, this.stateSvc.currentLanguageCode)
          .map(response => response.json())
          .toPromise();
  }

  initializeDropDowns() {
      this.fetchValueList('First-Val-List')
          .then(data => {
              this.firstValList = data;
              return this.fetchValueList('Second-Val-List')
          }).then(data => {
              this.secondValList = data;
              return this.fetchValueList('Third-Val-List')
          }).then(data => {
              this.thirdValList = data;
          })  }

Я визначив функції компонента, а потім викликав InitializeDropDowns () в ngOnInit.

Функція fetchValueList повертає Promise, тому перший виклик передає перший listCode, і коли Promise вирішується, значення повернення знаходиться в змінній даних у блоці .then, де ми можемо призначити його цій змінній this.firstValList. Оскільки функція повертає дані, ми знаємо, що сервіс закінчено, і безпечно знову зателефонувати за допомогою другого listCode, значення, що повертається, знаходиться в змінній даних у наступному блоці.

Ми можемо це зробити ланцюжком стільки разів, скільки потрібно для заповнення всіх змінних, а на останньому блоці коду ми просто опускаємо оператор return і блок закінчується.

Це дуже специфічний випадок використання, коли ми маємо єдину службу, яку потрібно викликати кілька разів, коли компонент ініціалізується, і коли сервіс повинен завершити отримання та повернути значення, перш ніж його можна буде знову викликати, але в цьому випадку, метод «Обіцяння / .тем» був ідеальним.


3
Це, звичайно, можливо також при спостереженні (вищого порядку). Наприклад, ви можете використовувати scan()для створення потоку послідовних спостережень. Однак ваш підхід, можливо, більш чіткий і простіший для розуміння.
lex82

1
Ви можете замінити "тоді" на "switchMap" і зробити саме те ж саме, що може спостерігатись.
Доктор К. Гіларій

1
Проблема з SwitchMap, як я розумію, полягає в тому, що він запускатиме всі запити паралельно і чекає, поки всі вони повернуться, потім поверне значення функції виклику, тоді як у моїй ситуації у мене є єдиний сервер, який я не можу дзвоніть кілька разів паралельно (оскільки сервер буде скидати незавершені запити, коли надходять нові), тому я повинен був переконатися, що кожен виклик до служби бази даних завершився перед початком нового дзвінка, і Обіцяння / тоді здавалося найкращим і можливо, єдиний спосіб вирішити це.
Стівен Р. Сміт

1
Чому ви не використали прикутий mergeMap? Наскільки я зрозумів ваш код, цей досить простий і робить роботу так само добре, як і ваш приклад. @ StephenR.Smith
Руда

1
@Ore Чи можете ви додати приклад коду для вирішення тієї ж проблеми, що й інша відповідь? Це буде хорошою рекомендацією і може стати гарною можливістю рефакторингу в майбутньому. Вимога полягає в тому, що який би код не міг паралельно викликати сервісну службу, він повинен зателефонувати, дочекатися повернення значення та зателефонувати ще раз.
Стівен Р. Сміт

20

Я вважаю, що всі інші відповіді повинні очистити ваші сумніви. Тим не менш, я просто хотів додати, що спостережливі дані базуються на функціональному програмуванні, і я вважаю дуже корисними функції, які поставляються з ним, як map, flatmap, уменьшення, zip. Послідовність, яку Інтернет досягає, особливо коли це залежить від запитів API, - жорстоке вдосконалення.

Я настійно рекомендую цю документацію , оскільки це офіційна документація reactiveX, і я вважаю, що вона є найбільш зрозумілою там.

Якщо ви хочете потрапити до спостережуваних даних, я б запропонував цей тришаровий пост: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

Хоча це призначено для RxJava, поняття однакові, і це дійсно добре пояснено. У документації на reakctiveX ви маєте еквіваленти для кожної функції. Ви повинні шукати RxJS.


18

Обіцянка:

  • Надайте єдине майбутнє значення;
  • Не лінивий;
  • Не скасовується;

Спостерігається:

  • З часом випускає кілька значень;
  • Ледачий;
  • Скасовується;
  • Підтримує оператори карти, фільтрування, зменшення та подібні оператори

При бажанні ви можете використовувати обіцянки замість спостереження під час виклику HTTP у Angular.


16

Огляд:

  • І обіцянки, і спостереження допомагають нам мати справу з асинхронними операціями. Вони можуть викликати певні зворотні дзвінки, коли ці асинхронні операції виконуються.
  • Обіцянка може поводитися лише з однією подією, спостережні - для потоків подій у часі
  • Обіцянки не можуть бути скасовані, коли вони очікують на розгляд
  • Емісію спостережуваних даних можна перетворити за допомогою операторів

Ви завжди можете використовувати спостережуване для боротьби з асинхронною поведінкою, оскільки спостерігаючий має всю функціональність, яку обіцянка пропонує (+ додатково). Однак іноді ця додаткова функціональність, яку пропонують спостерігачі, не потрібна. Тоді було б додатковим накладним імпортом бібліотеки для їх використання.

Коли використовувати обіцянки:

Використовуйте обіцянки, коли у вас є одна операція асинхронізації, з якої потрібно обробити результат. Наприклад:

var promise = new Promise((resolve, reject) => {
  // do something once, possibly async
  // code inside the Promise constructor callback is getting executed synchronously

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

//after the promise is resolved or rejected we can call .then or .catch method on it

promise.then((val) => console.log(val))      // logs the resolve argument
       .catch((val) => console.log(val));    // logs the reject argument

Тож обіцянка виконує якийсь код, де він або вирішує, або відхиляє. Якщо або вирішити, або відхилити, називається обіцянка переходить із стану, що перебуває у стані очікування, або до стану, яке було вирішено або відхилено . Коли стан обіцянки вирішено, then()метод викликається. Коли стан обіцянки відхилено, catch()метод викликається.

Коли використовувати спостережні дані:

Використовуйте спостережні дані, коли протягом потоку часу є потік (даних), який потрібно обробляти. Потік являє собою послідовність елементів даних , які робляться доступні в протягом довгого часу . Прикладами потоків є:

  1. Події користувача, наприклад, події клацання або клавіатури. Користувач генерує події (дані) з часом.
  2. Після того, як клієнт встановить з'єднання WebSocket з сервером, він виштовхує дані з часом.

У самому спостережуваному вказується, коли сталася наступна подія , коли виникає помилка або коли спостережуване завершено . Тоді ми можемо підписатися на цей спостережуваний, який його активує, і в цій підписці ми можемо передати 3 зворотних виклику (не завжди потрібно проходити у всіх). Один зворотний дзвінок, який потрібно виконати для успіху, один зворотний дзвінок за помилку та один зворотний дзвінок для завершення. Наприклад:

const observable = Rx.Observable.create(observer => {
  // create a single value and complete
  observer.onNext(1);
  observer.onCompleted();
});

source.subscribe(
  x => console.log('onNext: %s', x),   //  success callback
  e => console.log('onError: %s', e),  //  error callback
  () => console.log('onCompleted')     //  completion callback
 );

// first we log: onNext: 1
//  then we log: onCompleted

При створенні спостережуваної функції потрібна функція зворотного дзвінка, яка подає спостерігача як аргумент. На цьому спостерігач, то ви можете зателефонувати onNext, onCompleted, onError. Потім, коли спостерігається підписка на нього, він буде викликати відповідні зворотні дзвінки, передані в підписку.


9

Обіцянка - надайте єдине майбутнє значення. Не лінивий. Не може скасувати. Він або відхилить, або вирішить.

Спостерігається - надайте кілька майбутніх цінностей. Ледачий. Відмовитись. Він надає інші методи живої карти, фільтрує, зменшує.


8

Обіцяйте спочатку помітну схожість

  1. Обидва використовували для обробки асинхронного коду.
  2. Будь ласка, шукайте приклад обіцянок. Конструктор обіцянок передає довідкову функцію розв’язання, яка буде викликана, коли вона буде викликана з деяким значенням після завершення якоїсь задачі з асинхронізацією.

const promise = new Promise(resolve => {
  setTimeout(() => {
    resolve("Hello from a Promise!");
  }, 2000);
});

promise.then(value => console.log(value));

  1. Зараз помітний приклад. Тут також ми передаємо функцію спостережуваному, спостерігачеві для обробки завдання асинхронізації. На відміну від рішення в обіцянці, він має наступний метод і підписується замість того.

  2. Таким чином обидва обробляють завдання асинхронізації. Тепер побачимо різницю.


const observable = new Observable(observer => {
  setTimeout(() => {
    observer.next('Hello from a Observable!');
  }, 2000);
});

observable.subscribe(value => console.log(value));

Обіцяйте проти помітної різниці

Обіцяють

  1. Він вирішує або відхиляє одне значення і може одночасно обробляти завдання асинхронізації одного значення.
  2. Обіцянка, щойно вирішила значення асинхроніки, яке вона виконує, більше не може бути використана. Це лише одноразове використання, і тут воно не вистачає.
  3. Не можна скасувати
  4. Немає підтримки rxjs для операторів.

Спостерігається

  1. можливість випромінювати кілька асинхронних значень.
  2. Використовується для обробки потоку подій або значень. Вважайте, що у вас є масив численних завдань або значень, і ви хочете, щоб кожен раз, коли в нього вводиться значення, він повинен оброблятися автоматично. Щоразу, коли ви натискаєте значення на цей масив, усі його підписники автоматично отримують останнє значення.
  3. Спостереження корисні для спостереження за змінами вхідних даних, повторним інтервалом, трансляцією значень для всіх дочірніх компонентів, сповіщеннями про натискання веб-розетки тощо.
  4. Можна скасувати, використовуючи метод підписки в будь-який час.
  5. Ще одна остання хороша частина, яка обіцяє, - це підтримка операторів rxjs. У вас є багато операторів труб, які в основному відображають, фільтрують, переключають карту, комбінують найновіші тощо, щоб перетворити видимі дані перед передплатою.

введіть тут опис зображення



6

І обіцянки, і спостереження допомагають нам мати справу з асинхронними операціями. Вони можуть викликати певні зворотні дзвінки, коли ці асинхронні операції виконуються.

Angular використовує Observables, який є від RxJS замість обіцянок для роботи з HTTP

Below are some important differences in promises & Observables.

різниця між Обіцянками та Спостережними


1
Табличні дані здаються невірними, заголовок слід поміняти
Derrick.X

1
Будь ласка , змініть свій пост і показати реальний зміст як текст замість скріншотів. Інші не можуть копіювати та вставляти з ваших зображень. Детальніше дивіться тут . Дякую.
Панг

6

Обіцяння випускає одну подію, коли активність асинхронізації закінчується або завершується невдачею.

Спостережуване схоже на Потік (багатьма мовами) і дозволяє передавати принаймні нуль або більше подій, де зворотний виклик необхідний для кожної події.

Часто спостерігається перевагу перед Promise, оскільки це дає основні моменти Promise та багато іншого. З "Спостережуваним" не має значення, чи потрібно обробляти 0, 1 або різні події. Ви можете використовувати аналогічний API для кожного випадку.

Обіцянка: обіцянка випромінює єдине значення

Наприклад:

const numberPromise = new Promise((resolve) => {
    resolve(5);
    resolve(10);
});

numberPromise.then(value => console.log(value));
// still prints only 5

Спостерігається: випромінює кілька значень протягом певного періоду часу

Наприклад:

  const numberObservable = new Observable((observer) => {
        observer.next(5);
        observer.next(10);
    });

numberObservable.subscribe(value => console.log(value));
// prints 5 and 10

ми можемо думати про спостережуваний, як потік, який випромінює декілька значень за певний проміжок часу, і та сама функція зворотного виклику викликається для кожного випущеного елемента, тому за допомогою спостережуваного ми можемо використовувати один і той же API для обробки асинхронних даних. чи передаються ці дані як одне значення або кілька значень протягом певного проміжку часу.

Обіцянка:

  • Обіцянка - Не лінь
  • Обіцянку скасувати неможливо

Спостерігається:

  • Помітний - Ледачий. "Спостережуване" відбувається повільно. Він не називається, поки ми не підписалися на нього.
  • Спостережуване може бути скасовано за допомогою методу unsubscribe ()
  • Додаток, що спостерігається, забезпечує багато потужних операторів, таких як карта, передбачення, фільтрування, зменшення, повтор, повтор. Коли і т.д.

Кутові обіцянки проти спостережуваних


5

Promise випромінює одне значення, тоді як спостерігається - кілька значень. Так, під час обробки HTTP-запиту Promise може керувати однією відповіддю на той самий запит, але що робити, якщо на один запит є кілька відповідей, тоді нам доведеться використовувати Observable. Так, спостережуваний може обробляти кілька відповідей на один і той же запит.

Обіцяють

const promise = new Promise((data) =>
{ data(1);
  data(2);
  data(3); })
.then(element => console.log(‘Promise ‘ + element));

Вихідні дані

Promise 1

Спостерігається

const observable = new Observable((data) => {
data.next(1);
data.next(2);
data.next(3);
}).subscribe(element => console.log('Observable ' + element));

Вихідні дані

Observable 1
Observable 2
Observable 3

3

Нижче наведено кілька важливих відмінностей у обіцянках та спостереженнях.

Обіцяють

  • Випускає лише одне значення
  • Не можна скасувати
  • Не поділяється
  • Завжди асинхронний

Спостерігається

  • Випускає кілька значень
  • Виконує лише тоді, коли йому дзвонять або хтось підписується
  • Можна скасувати
  • Можна поділитись і передплатити цю загальну вартість декількома підписниками. І всі передплатники виконають за один момент часу.
  • можливо, асинхронний

Для кращого розуміння зверніться до https://stackblitz.com/edit/observable-vs-promises


3

Я бачу дуже багато людей, які використовують аргумент, що спостерігати "можна скасувати", але досить тривіально зробити обіцянку "скасовуваною"

function cancellablePromise(body) {
  let resolve, reject;
  const promise = new Promise((res, rej) => {
    resolve = res; reject = rej;
    body(resolve, reject)
  })
  promise.resolve = resolve;
  promise.reject = reject;
  return promise
}

// Example 1: Reject a promise prematurely
const p1 = cancellablePromise((resolve, reject) => {
  setTimeout(() => resolve('10', 100))
})

p1.then(value => alert(value)).catch(err => console.error(err))
p1.reject(new Error('denied')) // expect an error in the console

// Example: Resolve a promise prematurely
const p2 = cancellablePromise((resolve, reject) => {
  setTimeout(() => resolve('blop'), 100)
})

p2.then(value => alert(value)).catch(err => console.error(err))
p2.resolve(200) // expect an alert with 200


2

Коротка відповідь :

Спостережуваний є краще , вона має всі Обіцянки функції плюс додаткові функції.


Довга відповідь:

Обіцянки:

  • Одноразове використання "Повернення даних один раз"
  • Без скасування
  • Один слухач
  • Немає підтримки для розетки Один слухач

Спостерігається:

  • Повернення даних багато разів, коли дані змінюються
  • Скасувати підтримку
  • Підтримка розетки
  • Підтримуйте багатьох слухачів та повідомляйте їх про зміну даних
  • Підтримка карти, фільтрування, зменшення

Я не думаю, що можна сказати, що спостережувані об'єктивно кращі. У різних відповідях тут спостерігається кількість недоліків спостережуваних. Те, що мені виділяється, - це складність Спостережуваності, і що вони не працюють безпосередньо з режимом очікування / асинхронізації. Особисто мені важко працювати з ними, оскільки ви не можете визначити поведінку спостерігача при його використанні - ви повинні подивитися на код, який його створив. Тоді як із Обіцянням завжди точно знаєш, як вони працюють. Наприклад, іноді підписка на спостережуваний має побічні ефекти (наприклад, запит http), але іноді - ні.
Йона Апплетре

Для кутових це залежить від вашого випадку. у більшості випадків ми будемо працювати з сервісами та деякими даними, які вплинуть на різні місця, розетки, скасування, карту, фільтрування та зменшення. тому буде краще в тих випадках, коли обіцянки їх не підтримують. тому знову це залежить від вашого випадку
Амр Ібрагім

2

Хоча прийнята відповідь є загалом доброю, я не думаю, що вона підкреслює, що при роботі з кутовими компонентами ви майже завжди хочете використовувати спостережуваний, оскільки він підтримує скасування. Обіцяння не можна скасувати, і вони вирішаться, навіть якщо ваш компонент знищений. Кутовий має тенденцію прощати, поки цього не стане.

Наприклад, будь-яке ручне виявлення змін на знищеному компоненті спричинить виняток:

ngOnInit() {
  // promise api
  this.service.getData().then(d => {
     this.data = d;
     this.changeDetectorRef.detectChanges();
  });

  // observable api
  this.service.getData().pipe(takeUntil(this.unsubscribe)).subscribe((d) => {
     this.data = d;
     this.changeDetectorRef.detectChanges();
  });
}

Якщо ваш компонент знищений до того, як обіцянка буде вирішена, ви отримаєте attempt to use destroyed view помилку, коли обіцянка буде вирішена.

Крім того, якщо ви використовуєте спостережувані дані разом із takeUntil малюнком , то, як тільки ваш компонент буде знищений, підписка буде скасована.

Це трохи надуманий приклад, але виконання коду для знищеного компонента, ймовірно, призведе до помилок. Якщо ви насправді не хочете це зробити чомусь: с


2

Щось, на що я зіткнувся, що було не видно з першого читання підручника, і в документах була ідея багатоадресної передачі.

Переконайтеся, що ви знаєте, що за замовчуванням кілька підписок спричинить багаторазове виконання у "Видимому". Багаторазові підписки на один HTTP-дзвінок, що спостерігається, ініціюють кілька однакових HTTP-дзвінків, якщо ви.share() ввімкніть трансляцію.

Обіцянка змушує вас займатися однією справою, розгортати її дані, обробляти винятки, має мовну підтримку для класних речей, як-от асинхронізація / очікування, і в іншому випадку є досить босоніжними.

У спостережуваного багато дзвіночків, але вам потрібно зрозуміти, з якою силою ви працюєте, або це може бути неправильно використане.


2

Обіцянка:

Обробник подій Async - Об'єкт Promise являє собою можливе завершення (або збій) асинхронної операції та її отримане значення.

Синтаксис: нова Обіцянка (виконавець);

Наприклад:

var promise_eg = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

promise_eg.then(function(value) {
  console.log(value);
  // expected output: "foo"
});

console.log(promise_eg);

введіть тут опис зображення

Про обіцянку: У неї є один конвеєр, тому він повертає значення лише один раз, коли його буде викликано. його односторонній обробник, щойно зателефонувавши вам, не зможе скасувати. корисний синтаксис, з яким можна грати, коли () і потім ()

Спостережні дані:

Спостережувані - це ліниві колекції численних значень у часі. це дійсно чудовий підхід для асинхронних операцій. це може бути зроблено за допомогою rxjs, який має підтримку міжплатформних платформ, можна використовувати з кутовими / реагувати тощо.

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

Синтаксис: import * as Rx from "@reactivex/rxjs"; init:

Rx.Observable.fromEvent(button, "click"),
Rx.Subject()

тощо

підписатися: RxLogger.getInstance();

Наприклад:

import { range } from 'rxjs';
import { map, filter } from 'rxjs/operators';

range(1, 200).pipe(
  filter(x => x % 2 === 1),
  map(x => x + x)
).subscribe(x => console.log(x));

оскільки він підтримує багатопровідний конвеєр, ви можете підписатися на результат у різних місцях, введіть тут опис зображення він має багато можливостей, ніж обіцянки.

Використання: у нього більше можливостейmap, filter, pipe, map, concatMap etc



1

Спостереження часто порівнюють із обіцянками. Ось кілька ключових відмінностей:

Спостереження є декларативними; обчислення не починається до підписки. Обіцяння виконувати негайно по створенню. Це робить спостереження корисними для визначення рецептів, які можна виконувати, коли потрібен результат.

Спостережні дані дають багато значень. Обіцянки дають одне. Це робить спостережні дані корисними для отримання кількох значень у часі.

Спостережні дані розрізняють ланцюжок та передплату. Обіцянки мають лише пункти .then (). Це робить спостережливі корисними для створення складних рецептів перетворень, які використовуються в інших частинах системи, не викликаючи виконання роботи.

Спостерігачі передплатники () відповідають за обробку помилок. Обіцяє потік помилок дитини обіцянки. Це робить спостережні дані корисними для централізованого та передбачуваного поводження з помилками.

Це найпростіша різниця, яку ви можете знайти в документах ANGULAR.IO. відповідь про відпочинок дає більшість правильна у своєму місці


1
  1. Обіцянки зосереджені лише на одиничних значеннях або на вирішеннях, спостережувані - це потік даних.

  2. Спостереження можна скасувати, але обіцянки скасувати неможливо.

Найменш відомий, щонайменше, для мене

  1. Обіцянки завжди мають асинхронний характер, але спостережувані можуть бути як синхронні, так і асинхронні.

0
  1. обіцянка нетерпляча, тоді як спостерігаючий - лінивий,
  2. обіцянка завжди асинхронна, тоді як Спостережуване може бути або синхронним, або асинхронним,
  3. Обіцянка може надати єдине значення, тоді як Спостережуване - це
    потік значень (від 0 до кількох значень)
  4. Ви можете застосувати оператори RxJS до спостережуваного, щоб отримати новий індивідуальний потік.

-1

Спостереження та обіцянки допомагають нам працювати з асинхронними функціоналами в JavaScript / typecript. Вони дуже схожі у багатьох випадках, проте між ними все ж є деякі відмінності.

введіть тут опис зображення


1
Будь ласка , змініть свій пост і показати фактичний текст замість скріншотів. Інші не можуть копіювати та вставляти з ваших зображень. Детальніше дивіться тут . Дякую.
Панг

Крім того, що ні код , але простий інформації, тому я думаю , що це нормально , щоб відправити його в якості зображення
Alator

1
зупинити копіювання вставляти з відео на YouTube Kudvenkat. Від мене відхилився! :)
Pratik

-2

На цю тему вже багато відповідей, тому я не додав би зайвого.

Але тому, хто щойно почав вивчати Спостережливе / Кутове і цікавиться, який з них використовувати порівняти з Promise , я б рекомендував вам зберігати все спостережуване та перетворювати всі існуючі обіцянки у вашому проекті на спостережувані.

Просто тому, що самі Angular Framework та його спільнота використовують спостережуване. Тож було б вигідно, коли ви інтегруєте рамкові послуги або сторонні модулі та зв'язуєте все разом.


Хоча я ціную всі голоси, але все ж наполягаю на своїй думці вище, якщо хтось не додасть належного коментаря, щоб перерахувати декілька сценаріїв, які все ще можуть бути корисними у вашому проекті Angular, щоб використовувати Обіцянки над Спостережними.

Звичайно, жодна думка не є 100% правильною у всіх випадках, але, принаймні, я думаю, що 98% часу для регулярних комерційних проектів, що реалізуються в рамках Angular Framework, спостерігається - це правильний шлях.

Навіть якщо вам не сподобається на початковому етапі вашого простого хобі-проекту, незабаром ви зрозумієте, що майже всі компоненти, з якими ви взаємодієте в Angular, і більшість Angular дружелюбних третіх сторін використовують спостереження, і тоді ви в кінцевому підсумку постійно перетворював вашу Обіцянку на Спостережливе, щоб спілкуватися з ними.

Ці компоненти включають, але не обмежуються ними: HttpClient, Builder форм, модулі / діалоги кутових матеріалів, магазин / ефекти Ngrx та ngx-bootstrap.

Насправді єдина Обіцянка від Angular eco-системи, якою я займався за останні 2 роки APP_INITIALIZER.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.