「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」
前言
在 JavaScript 中 Observables 和 Promises 都能够解决异步问题。那我们在开发的时候选择哪种会比较方便快捷呢,这次我们来对比一下他们之间的用法用什么区别。
区别
Promises 和 Observables 处理异步的方法完全不一样,主要表现在以下几点。
单值和多值
Promise 的状态一旦变成 fulfilled(已完成),就无法再次改变状态,这就导致了它只能触发(reject, resolve)一次值。而Observables能够触发多次值,直到观察者完成或者取消订阅,否则订阅者将一直接收结果。
// Promise
const promise = new Promise((resolve) => {
// 只会触发第一次 resolve
// 触发后状态不会再改变
resolve(1)
resolve(2)
resolve(3)
});
而Observables是这样的:
const observable = Rx.Observable.create((observer) => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
observer.next(4);
})
observable.subscribe(
v => console.log(v),
err => console.log(err),
done => console.log("completed")
);
可以看到直到 observer 已完成之前,订阅者可以一直接收消息。这使得Observables可以很好的接收流式数据。
Observable 订阅可以取消;Promise 不能取消
一旦我们开始了Promise,那么我们不能再取消它,Promise 会被它的回调函数使用resolve或reject进行响应。而Observable是可以取消的。一但订阅者被创建它可以随时被观察者移除。这样当用户离开页面时我们可以停止订阅。
// 可以使用 unsubscribe 停止订阅
const observable = Rx.Observable.create((observer) => {
let i = 0;
const token = setInterval(() => {
observer.next(i++);
}, 1000);
});
const subscription = observable.subscribe(value => console.log(value + '!'));
subscription.unsubscribe();
或者通过take 或 takeUntil 方法进行控制停止。
// 使用 take
const observable = Rx.Observable.create((observer) => {
let i = 0;
const token = setInterval(() => {
observer.next(i++);
}, 1000);
});
const subscription = observable.take(5).subscribe(x => console.log(x));
执行顺序
Promise 会在创建的时候就执行构造函数的代码,而Observables会在subscribe时才会被执行。
Promise
const foo = new Promise((resolve) => {
console.log('promise');
resolve(true);
});
// 会直接打印出 promise
const observable = new Rx.Observable(observer => {
console.log('1. Execution of observable body');
observer.next(1);
observer.complete();
});
// 创建时不会执行里面的代码,所以没有打印
observable.subscribe(() => {
console.log('2. Execution of subscribe callback')
});
// 当执行 subscribe 后开始执行代码,输出顺序为
// 1. Execution of observable body
// 2. Execution of subscribe callback
运行时执行时机
在Promises中,一旦执行了resolved,将在微任务队列中排队回,也就是说他会在当前宏任务之后执行。比如:
console.log('1. Start');
setTimeout(() => {
console.log('2. Timeout callback')
}, 0);
Promise.resolve().then(() => {
console.log('3. Promise callback')
});
console.log('4. End');
// 1. Start
// 4. End
// 3. Promise callback
// 2. Timeout callback
我们无法改变这种行为。
在Observables中可以使用 Scheduler 控制订阅何时启动、通知何时发出的程序。先看下面这个例子,我们不使用 Scheduler 调度。
var observable = Rx.Observable.create(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
})
console.log('just before subscribe');
observable.subscribe({
next: x => console.log('got value ' + x),
complete: () => console.log('done'),
});
console.log('just after subscribe');
/** 打印顺序为:
just before subscribe
got value 1
got value 2
got value 3
done
just after subscribe
*/
我们可以使用 Scheduler 来改变执行顺序
var observable = Rx.Observable.create(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
}).observeOn(Rx.Scheduler.asap);
console.log('just before subscribe');
observable.subscribe({
next: x => console.log('got value ' + x),
complete: () => console.log('done'),
});
console.log('just after subscribe');
/** 打印顺序为:
just before subscribe
just after subscribe
got value 1
got value 2
got value 3
done
*/