Створіть одноразову підписку


182

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

Чи є щось на кшталт:

observable.subscribeOnce(func);

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

Відповіді:


319

Чи не 100% впевнені в тому , що вам потрібно, але якщо ви хочете , щоб спостерігати перше значення, а потім використовувати або first()чи take(1):

observable.first().subscribe(func);

Примітка: .take(1)і .first()обидва скасовуються підписки, коли їх умова буде виконана

Оновлення від RxJS 5.5+

З коментаря Coderer .

import { first } from 'rxjs/operators'

observable
  .pipe(first())
  .subscribe(func);

Ось чому


33
Чи підписка автоматично прибирається після?
Берклі Мартінес

50
Так. Візьміть і спочатку скасуйте підписку, коли буде виконано їхню умову.
Брендон

20
Чому в документації не сказано, що вона автоматично розпоряджається підпискою?
jzig

17
Це загальне правило RxJS, що підписки розміщуються, коли закінчується спостережуваний потік. Це означає, що будь-який оператор, який "скорочує" потік (або перетворює його в інший тип потоку), скасує підписку на вихідний потік, коли їх робота завершиться. Я не впевнений, де або якщо це зазначено в документації.
Брендон

37
Якщо хтось до цього приходить у 2018 році, ви насправді хочете observable.pipe(first()).subscribe(func), звідки firstпоходить rxjs/operators.
Coderer

32

RxJS має найкращу документацію, яку я коли-небудь стикався. Після наступного посилання ви перейдете до надзвичайно корисної таблиці, яка відображає випадки використання операторів. Наприклад, в розділі «Я хочу , щоб посісти перше значення» випадок використання трьох операторів: first, firstOrDefault, і sample.

Зауважте, якщо спостережувана послідовність завершується без сповіщень, то firstоператор повідомляє передплатників про помилку, в той час як firstOrDefaultоператор надає передплатникам значення за замовчуванням.

пошук оператора


3

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


дуже цікаво, це також означає , що ми можемо тільки , що робить його одним лайнерawaitpromise
Louie Almeda

@LouieAlmeda ви могли б надати нам один приклад лайнера?
Адо Рен

Привіт @AdoRen, я пояснив техніку у відповіді тут для вас, я сподіваюся, що це допоможе.
Луї Альмеда

2

Щоб доповнити відповідь @ Брендона , використання first()або подібне також має важливе значення для оновлення її BehaviorSubjectна основі Observable. Наприклад (неперевірений):

var subject = new BehaviorSubject({1:'apple',2:'banana'});
var observable = subject.asObservable();

observable
  .pipe(
    first(), // <-- Ensures no stack overflow
    flatMap(function(obj) {
      obj[3] = 'pear';
      return of(obj);
    })
  )
  .subscribe(function(obj) {
    subject.next(obj);
  });

2

Чиста та зручна версія

Розширення на дивовижну відповідь M Fuat NUROĞLU щодо перетворення спостережуваного в обіцянку, ось дуже зручна версія цього.

const value = await observable.toPromise();

console.log(value)

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

Це особливо зручно, коли вам потрібно отримати кілька значень із кількох спостережуваних. Охайний і чистий.

const content = await contentObservable.toPromise();
const isAuthenticated = await isAuthenticatedObservable.toPromise();

if(isAuthenticated){
   service.foo(content)
}

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

Я не впевнений, чи є компроміси з таким підходом, сміливо повідомте мене в коментарях, щоб ми знали.

PS Якщо вам сподобалась ця відповідь, не забудьте також відповісти на відповідь M Fuat NUROĞLU :)


0

У мене було подібне питання.

Нижче зателефонували ще пізніше від різних змінників штатів. Як я цього не хотів.

function foo() {
    // this was called many times which was not needed
    observable.subscribe(func);
    changeObservableState("new value");
}

Я вирішив спробувати unsubscribe()після підписки, як показано нижче.

function foo() {
    // this was called ONE TIME
    observable.subscribe(func).unsubscribe();
    changeObservableState("new value");
}

subscribe(func).unsubscribe();це як subscribeOnce(func).

Я сподіваюся, що і вам це допомогло.

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