见面推迟

在上一篇文章中,我们研究了如何创建自己的RxJS语句。现在,我想谈谈一个鲜为人知的创建运算符defer-并说明在某些情况下如何使用它


假设您需要使一个操作员接受一个函数并在第一次接收到值时仅执行一次。我们以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;
        }
      })
    );
  };
}

代码很清楚-它tap用于运行函数,run仅需执行一次标志即可。现在我们使用运算符。


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

source.subscribe(console.log);

一切正常,加号仅在第一个发出时显示在控制台中。现在添加订户。


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

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

如果您查看控制台-只有一个加号。问题在于两个订户使用相同的词法环境并引用相同的变量run我们需要一种方法来推迟线程的创建,直到有人订阅为止。


会帮助 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;
          }
        })
      );
    });
  };
}

操作员defer接受应返回的功能ObservableInput其中的代码defer仅在订阅时执行,而不在创建时执行。使用这种方法并感谢js闭包,每个订阅者都使用自己的词汇环境。


让我们创建一个简单的实现defer以更好地理解。


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

defer 返回一个新的流,该流是在工厂函数预订时创建的,并将用作源。


这里有更多有用的例子defer假设我们有一个表达式,当某人注册时需要计算该表达式。例如


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

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

在此示例中,每个订户将收到相同的随机值。您可以对其进行更正,以便在订阅时(而不是在宣布时)对表达式进行计数。


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);

另一个例子是当您需要延迟承诺的执行时。


// 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);

无论侦听器有多少,都将立即执行承诺。您可以使用来使承诺看起来像流(即懒惰)defer


All Articles