上面介绍一个少有人晓得的 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…