上面介绍一个少有人晓得的observable -- defer,如何应用,什么时候应用
读这篇文章之前,你须要对rxjs根底用法有肯定的理解


假如咱们须要写一个自定义operator叫做tapOnce。接管一个函数当作参数,只有流的第一次触发时才执行

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

这段代码简略直观,在tap的根底上,用了一个变量来管制执行次数,调用一下

const test$ = interval(1000).pipe(tapOnce((d) => console.log('', d)));test$.subscribe();// 1s之后打印 0

运行很失常,在流第一次触发的时候打印狗头。
要是再加一个订阅者呢?

const test$ = interval(1000).pipe(tapOnce((d) => console.log('', d)));test$.subscribe();test$.subscribe();// 1s之后打印 0

后果只打印了一遍,这是因为两个订阅者订阅同一个流,应用同一个run变量。
想要打印两遍,咱们就须要一个可能在订阅时才创立流的性能。
defer就是用来做这件事的
改良一下

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

defer接管一个返回类型为observable的函数。只有当defer被订阅了,函数才会执行。而不是在创立时。而后利用js闭包,让每个订阅者有本人的作用域。

通过简略的抽象类看一下defer到底是怎么实现的

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

defer返回一个新的observable。当有订阅者订阅的时候,就会执行工厂办法,创立并返回新的observalbe。

看看defer还能在什么场景下发挥作用,假如有一个这样的需要,每次订阅的时候返回一个随机数

const randNum = of(Math.random()); randNum.subscribe(console.log);randNum.subscribe(console.log);

这里每一个订阅者打印的值是一样的,咱们能够用defer改良一下

const randNum = defer(() => of(Math.random()));randNum.subscribe(console.log);randNum.subscribe(console.log);// 等同于这种写法const randNum2 = () => of(Math.random());randNum2().subscribe(console.log);randNum2().subscribe(console.log);

另一种场景是咱们想要提早一下promise的执行工夫。当有订阅者的时候,promise才执行。实现一个lazyPromise

// 此时console.log('promise')曾经执行const promise = new Promise((resolve) => {  console.log('promise');  setTimeout(() => resolve('promise'), 1000);});// console.log('lazy promise');只有当被订阅才执行const lazyPromise = defer(() => {  return new Promise((resolve) => {    console.log('lazy promise');    setTimeout(() => resolve('promise'), 1000);  });});lazyPromise.subscribe(console.log);

Promises天生就是热流,忽视订阅者。咱们能够通过defer,把promise变成一个Observable-like

代码: https://stackblitz.com/edit/r...