Treffen Sie aufschieben

In einem früheren Artikel haben wir uns angesehen, wie wir unsere eigenen RxJS-Anweisungen erstellen. Jetzt möchte ich über einen wenig bekannten Erstellungsoperator sprechen - defer- und erklären, wie Sie ihn in bestimmten Situationen verwenden können


Angenommen, Sie müssen einen Operator erstellen, der eine Funktion übernimmt und sie nur einmal ausführt, wenn sie zum ersten Mal einen Wert erhält. Wir implementieren es unter dem Namen tapOnce


function tapOnce<T>(fn: Function): OperatorFunction<T, T> {
  return function(source: Observable<any>) {
    let run = false;
    return source.pipe(
      tap(() => {
        if (!run) {
          fn();
          run = true;
        }
      })
    );
  };
}

Der Code ist klar - er wird tapzum Ausführen der Funktion verwendet, das Flag wird rundazu nur einmal benötigt. Jetzt benutzen wir den Operator.


const source = interval(5000).pipe(
  tapOnce(() => console.log('+')
));

source.subscribe(console.log);

Alles funktioniert, das Pluszeichen wird erst beim ersten Senden in der Konsole angezeigt. Fügen Sie nun die Abonnenten hinzu.


const source = interval(5000).pipe(
  tapOnce(() => console.log('+')
));

source.subscribe(console.log);
source.subscribe(console.log);

Wenn Sie sich die Konsole ansehen, gibt es nur ein Plus. Das Problem ist, dass beide Abonnenten dieselbe lexikalische Umgebung verwenden und auf dieselbe Variable verweisen run. Wir brauchen eine Möglichkeit, die Erstellung eines Threads zu verschieben, bis sich jemand anmeldet.


Wird helfen defer


import { defer } from 'rxjs';

function tapOnce<T>(fn: Function): OperatorFunction<T, T> {
  return function(source: Observable<any>) {
    return defer(() => {
      let run = false;
      return source.pipe(
        tap(() => {
          if (!run) {
            fn();
            run = true;
          }
        })
      );
    });
  };
}

Der Operator deferakzeptiert eine Funktion, die zurückgegeben werden soll ObservableInput. Der darin enthaltene Code deferwird nur beim Abonnement und nicht während der Erstellung ausgeführt. Mit diesem Ansatz und dank js Schließung verwendet jeder Abonnent seine eigene lexikalische Umgebung.


Lassen Sie uns unsere einfache Implementierung deferzum besseren Verständnis erstellen .


function defer(observableFactory: () => ObservableInput<any>) {
  return new Observable(subscriber => {
    const source = observableFactory();
    return source.subscribe(subscriber);
  });
}

defer Gibt einen neuen Stream zurück, der zum Zeitpunkt des Abonnements von der Factory-Funktion erstellt wird und als Quelle verwendet wird.


Hier sind weitere Beispiele, wo es nützlich sein wird defer. Angenommen, wir haben einen Ausdruck, der gezählt werden muss, wenn sich jemand anmeldet. zum Beispiel


const randNum = of(Math.random());

randNum.subscribe(console.log);
randNum.subscribe(console.log);

In diesem Beispiel erhält jeder Teilnehmer den gleichen Zufallswert. Sie können es so korrigieren, dass der Ausdruck beim Abonnieren gezählt wird, nicht beim Ansagen.


const randNum = defer(() => of(Math.random()));

randNum2.subscribe(console.log);
randNum2.subscribe(console.log);

// The same concept as using a function
const randNum = () => of(Math.random());
randNum2().subscribe(console.log);
randNum2().subscribe(console.log);

Ein weiteres Beispiel ist, wenn Sie die Ausführung eines Versprechens verzögern müssen.


// This already executing regardless the numbers of handlers
const promise = new Promise(resolve => {
  resolve();
});

// Deferring the creation of the promise until someone subscribes
const promiseDefered = defer(() => {
  return new Promise(resolve => {
    resolve();
  });
});

promiseDefered.subscribe(console.log);

Versprechen werden sofort ausgeführt, unabhängig von der Anzahl der Zuhörer. Sie können ein Versprechen mit einem Stream (d defer. H. Faul) aussehen lassen .


All Articles