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


182

Мне нужно создать подписку на Observableтот, который сразу же удаляется при первом вызове.

Есть ли что-то вроде:

observable.subscribeOnce(func);

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

Ответы:


319

Не 100% уверены в том , что вам нужно, но если вы хотите , чтобы наблюдать первое значение, а затем использовать либо first()или take(1):

observable.first().subscribe(func);

примечание: .take(1)и .first()оба автоматически отписываются, когда выполняется их условие

Обновление от RxJS 5.5+

Из комментария Кодерера .

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

Если вы хотите вызывать Observable только один раз, это означает, что вы не собираетесь ждать от него потока. Таким образом, использование toPromise()вместо subscribe()было бы достаточно в вашем случае, так как toPromise()не требует отписки.


очень интересно, это также означает , что мы можем только , что делает его одним лайнерawaitpromise
— Louie Almeda

@LouieAlmeda не могли бы вы привести пример с одним лайнером?
— Ado Ren

Привет @AdoRen, я изложил эту технику в ответе здесь для вас, надеюсь, это поможет.
— Луи Альмеда

2

В дополнение к ответу @ Brandon , использование 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.