最近在学习RxJS,它是使用 Observables 的响应式编程的库,它使编写异步或基于回调的代码更容易。web
下面主要介绍Observables 与 promise的不一样点。编程
const numberPromise = new Promise((resolve) => {
resolve(5);
resolve(10)
});
numberPromise.then(value => console.log(value));
// 输出 只会有 5
复制代码
下面改写为observables的写法,使用 next 替代 promise 的 resolve, 用subscribe 取代then来订阅结果。promise
const Observable = require('rxjs/Observable').Observable;
const numberObservable = new Observable((observer) => {
observer.next(5);
observer.next(10);
});
numberObservable.subscribe(value => console.log(value));
// 输出 5 10
复制代码
observable是能够连续订阅的,这个和promise的区别很大。平时咱们遇到的可能大多数都是一个请求一个响应的这种状况,可是咱们也会存在一些状况:bash
const numberObservable = new Observable((observer) => {
let i = 0;
setInterval(() => {
observer.next(i++);
}, 1000);
});
numberObservable.subscribe(value => console.log(value));
// 输出 0 1 2 3 4 5
复制代码
const promise = new Promise((resolve) => {
console.log('promise call')
resolve(1);
console.log('promise end')
})
// 执行这段代码 promise call 和 promise end 会当即执行
const observable = new Observable(() => {
console.log('I was called!');
});
// 此时并无console
// 只有 observable.subscribe(); 这个时候 I was called!才会被打印出来。
复制代码
上面两段代码就对比能够发现Observables是lazy的,只有当有人去订阅(subscribe)的时候Observables才会真正的被执行。异步
若是上方setInterval的函数写在promise里面,可是没有promise.then之类的函数就会形成资源的浪费,而在observable里面,不订阅连内存都不会分配。函数
promise默认是不能取消的,可使用promise的实现库 bluebird 来实现。bluebird是彻底兼容promise而且添加了一些有用的方法。学习
const Observable = require('rxjs/Observable').Observable;
const observable = new Observable((observer) => {
let i = 0;
const token = setInterval(() => {
observer.next(i++);
}, 1000);
return () => clearInterval(token);
});
const subscription = observable.subscribe(value => console.log(value + '!'));
setTimeout(() => {
subscription.unsubscribe();
}, 5000)
// 结果
0!
1!
2!
3!
复制代码
这个地方须要注意的是, subscribe 返回的不是一个Observable! 这就是说不能和promise同样链式的subscribe。subscribe返回的是一个对于指定observable的 Subscription。他只有一个方法能够调用,就是unsubscribe。ui
promise 是比较激进的,在一个promise被建立的时候,他就已经执行了,而且不能重复的被执行了。spa
let time;
const waitOneSecondPromise = new Promise((resolve) => {
console.log('promise call')
time = new Date().getTime();
setTimeout(() => resolve('hello world'), 1000);
});
waitOneSecondPromise.then((value) => {console.log( '第一次', value, new Date().getTime() - time)});
setTimeout(() => {
waitOneSecondPromise.then((value) => {console.log('第二次', value, new Date().getTime() - time)});
}, 5000)
// 输出结果是 promise call
第一次 hello world 1007
第二次 hello world 5006
复制代码
上面这个例子中,我建立了一个promise,他是当即执行的setTimeout,因此在第一个then函数中打印时间间隔是约等于 1s,这个是符合咱们预期的,但愿能在1s后获取到promise的返回值 。 第二个then函数是在 5s以后执行的,第二次hello word 和promise的开始时间差约为5s。由于在该promise建立的1s后已经resolve,此时就直接调用then函数,不会延时1s执行。由于promise是只会执行一次。code
那么再来看obsrvables
const Observable = require('rxjs/Observable').Observable;
let time;
const waitOneSecondObservable = new Observable((observer) => {
console.log('I was called');
time = new Date().getTime();
setTimeout(() => observer.next('hey girl'), 1000);
});
waitOneSecondObservable.subscribe((value) => {console.log( '第一次', value, new Date().getTime() - time)});
setTimeout(() => {
waitOneSecondObservable.subscribe((value) => {console.log( '第二次', value, new Date().getTime() - time)});
}, 5000)
// 输出
I was called
第一次 hey girl 1003
I was called
第二次 hey girl 1003
复制代码
这个就是咱们但愿的结果,他在每一次订阅的时候都会从新去执行被监听的函数,不论何时想要用这个函数,只须要从新 subscribe 一下就能够。
用observable已经能够实现屡次订阅,可是这有时候可能不能符合咱们的业务场景,在http请求中,咱们可能但愿只发一次请求,可是结果被多个订阅者共用。 Observables 自己没有提供这个功能,咱们能够用 RxJS 这个库来实现,它有一个 share 的 operator。
const waitOneSecondObservable = new Observable((observer) => {
// 发送http请求
});
const sharedWaitOneSecondObservable =
waitOneSecondObservable.share();
sharedWaitOneSecondObservable.subscribe(doSomething);
sharedWaitOneSecondObservable.subscribe(doSomethingElse);
// 使用了share,虽然subscribe了屡次,可是仅发送一次请求,share告终果。
复制代码
const promise = new Promise((resolve) => {
resolve(5);
});
promise.then(value => console.log(value + '!'));
console.log('And now we are here.');
//
And now we are here.
5!
复制代码
虽然在promise里面 resolve了一个同步的东西,但他仍是会先执行完代码。
const Observable = require('rxjs/Observable').Observable;
const observable = new Observable((observer) => {
// observer.next(5);
setTimeout(() => {
observer.next(5);
})
});
observable.subscribe(value => console.log(value + '!'));
console.log('And now we are here.');
//
这个若是是直接next 5,则输出是 5! -> And now we are here.
采用setTimeout next 5, 则相反 And now we are here.-> 5!
复制代码
promise一直是异步, Observables则比较灵活,是否为异步得根据本身的函数来定,这点也比较危险。rxjs中有一些操做符可让监听强制为异步的方式,例如 observeOn。