RxJS Observables vs Promise 之简单对比

最近在学习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

  • setInterval,须要resolve多个值
  • webSockets
  • DOM events
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。

相关文章
相关标签/搜索