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


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.