携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
Rxjs VS Promise
如果我们在项目中没有使用Rxjs,那必然会使用Promise(当然也可以使用基于Promise的第三方库),在某些方面,他们有相同之处,也有很大的区别。
单值和多值
Promise是单值的,一旦Promise的状态变为Resolved,Promise的值就定下来了不能再次被改变,但是一个Promise可以被多次订阅,他们会收到同样的值。
const p1 = new Promise((resolve, reject) => {
resolve(1);
resolve(2);
});
p1.then((x) => {
console.log(x);
});
// 只能接收到1,
Rxjs则不同,因为流是一个按时间顺序排列数据序列集合,是可以发出多个值的,直到这个流完成。
const source$ = new Observable((observer) => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
});
source$.subscribe((x) => {
console.log(x);
});
Observable和Promise都是可以被多次订阅的,这一点是类似的。
立即执行和惰性执行
当你new了一个Promsie,这个Promise会立即执行,即使还没有订阅,也就是还没有then。Observable则是惰性执行,你new了一个Observable,但是它并不会执行,只有当你subscribe订阅的时候才会执行。这一点非常重要,即使你很擅长Promise,在Angular中使用httpClient去发送网络请求的时候这是一个必踩的坑,就是你的Observable不会立即去发送网络请求,直到你订阅了它。
const p1 = new Promise((resolve, reject) => {
// 立即执行
resolve(1);
resolve(2);
});
const source$ = new Observable((observer) => {
console.log('start!');
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
});
// 订阅了才执行
source$.subscribe((x) => {
console.log(x);
});
我觉得这个是Rxjs实现的很好的一点,如果你的网络请求用Promise来实现,当你定义了一个Promise的时候,你的网络请求已经发出去了,但是后面由于一些情况,并没有then,这就造成了浪费了,但是Observable则很好的优化了这一点。
可取消和不可取消
Promise的订阅是不可取消的,Observable的订阅是可以取消订阅的。
const source$ = new Observable((observer) => {
let i=0;
let id = setInterval(() => {
observer.next(i++);
}, 1000);
return () => {
clearInterval(id);
};
});
let subscription = source$.subscribe((x) => {
console.log(x);
});
setTimeout(() => {
subscription.unsubscribe();
}, 5000);
console.log('End');
// End
// 0
// 1
// 2
// 3
一次执行和多次执行
Promise只会执行一次,而Observable可以有多个订阅者,而且会执行多次。
const source$ = new Observable((observer) => {
let i=0;
observer.next(i++);
observer.next(i++);
observer.complete();
});
let subscription1 = source$.subscribe((x) => {
console.log('第一个: ', x);
});
let subscription2 = source$.subscribe((x) => {
console.log('第二个: ', x);
});
console.log('End');
// 第一个: 0
// 第一个: 1
// 第二个: 0
// 第二个: 1
// End
同步和异步
对于Promise,订阅函数then永远是异步的。Observable的订阅函数,可能是异步的,也可能是同步的。
const p1 = new Promise((resolve, reject) => {
// 立即执行
resolve(1);
resolve(2);
});
p1.then((data) => {
// 异步
...
});
console.log('End');
Observable可异步,可同步,要根据具体情况来看。如果使用interval创建的Observable,就是异步的,如果使用of创建的Observable,则是同步的,这一点非常重要。但是,即使使用of创建的Observable,我们也可以指定异步调度器,让它专为异步。
const source$ = interval(1000).pipe(take(5));
source$.subscribe((x) => {
console.log(x);
});
console.log('End');
const source$ = of(1,2,3);
source$.subscribe((x) => {
console.log(x);
});
console.log('End');
const source$ = of(1,2,3);
source$.pipe(subscribeOn(asyncScheduler)).subscribe((x) => {
console.log(x);
});
console.log('End');
至此,是不是对Rxjs和Promise有了更进一步的理解了。 再来看一下在React中怎么使用Rxjs吧,这一部分暂时合并在本篇文章中,内容篇幅比较少,不适合单独写一篇文章。
Rxjs在React中的应用
Rxjs并不是Angular的专属库,JS的前端框架都是可以使用Rxjs的,只是Angular深度集成了Rxjs。这里只举几个简单的栗子。
在React组件中使用Rxjs,最简单的用法就是:在组件初始挂载的时候,订阅一个数据流;在组件卸载的时候,取消订阅这个数据流。
订阅事件流
import { fromEvent } from "rxjs";
const Component = () => {
useEffect(() => {
let subscription = fromEvent(document.body, "click").subscribe((e) => {
console.log("click", e);
});
return () => subscription.unsubscribe();
}, []);
return <div></div>;
};
只要掌握了Rxjs,无论在哪个框架里使用,其实都是一样的。
总结
又回到了只是积累的这个问题上,如果之前就对Promise有深入的理解,那对比学习Rxjs的时候就相对轻松一些,两个都有深入理解之后,对比两者的时候就更加游刃有余了。