200行代码理解 RxJS 的核心概念

本文通过10个逐步深入的示例,使用不到200行代码来理解并实现RxJS的核心概念,包括Observable、of、fromEvent、from、interval等操作符的实现,探讨链式调用与pipe调用的优劣,旨在帮助开发者深化对RxJS响应式编程的理解。
摘要由CSDN通过智能技术生成

RxJS 非常强大,各种操作符连接在一起便能让数据流动到需要用到它的地方,有人甚至觉得 RxJS 是魔法;

然而,太阳底下无新事,本教程将一步步揭开 RxJS 的神秘面纱;

这篇文章会通过 10 个有趣的小 demo 渐进式的实现 RxJS 的核心功能,其中包括:

  • 类:Observable 的实现
  • 类的方法:subscribe,pipe 的实现
  • 创建类操作符:of,from,fromEvent,interval,timer 的实现
  • 过滤类操作符:filter,take 的实现
  • 工具类操作符:tap 的实现
  • 组合类操作符:merge 的实现

其中还包括 RxJS v5 链式调用 和 RxJS v6 通过 pipe 来调用 的各自实现。

而这一切,只有200行不到的代码,如果感兴趣,开始你的愉快之旅吧!

写在前面

为了保证阅读效果,建议读者边阅读边动手实操,点击这里可以下载相应的代码。

1、实现一个 Observable

RxJS 的一切起源与 Observable,Observable 是 RxJS 世界的基石,没有它,响应式无重谈起。

Observable 表示一个可观察对象,他表示一个可调用的未来值或事件的集合。

比如有以下代码:

import {
    Observable } from 'rxjs';

const dataStream$ = new Observable(observer => {
   
  observer.next(1);
  setTimeout(() => {
   
    observer.next(2);
    observer.complete();
  }, 1000)
  observer.next(3);
});

const observer = {
   
  next: x => console.log(x),
  error: err => console.error(err),
  complete: () => console.log('done'),
}

dataStream$.subscribe(observer);

这段代码引用的是官方的 Observable, 它在运行后会首先打印一个1,接着打印一个3,隔一秒后会再打印一个2,最后运行结束

仔细观察 Observable 方法,他会接受一个方法传进它的构造函数,这个方法接受一个对象,对象上有 next, error, complete 等属性,但是这个对象是 Observable 实例在调用 subscribe 方法时才传进去的:

有了上面的思路,我们可以大胆的构造出自己的 Observable, 如下:

export class Observable {
   
  _subscribe;
  constructor(subscribe) {
   
    this._subscribe = subscribe;
  }
  subscribe(observer) {
   
    this._subscribe(observer);
  }
}

把官方的 Observable 替换成自己的 Observable 会发现输出没什么差异。

没错,Observable 的核心就是这么简单。到现在,我们只用了9行代码实现便了Rxjs的核心概念之一 —— Observable

2、实现创建类操作符 of

创建类操作符中,最容易理解的莫过于 of,那么我们就先实现 of 操作符。

比如有如下代码:

import {
    of } from 'rxjs';

const dataStream$ = of(1, 2, 3)

const observer = {
   
  next: x => console.log(x),
  error: err => console.error(err),
  complete: () => console.log('done'),
}

dataStream$.subscribe(observer);

它在运行后会首先打印一个1,接着打印一个2,再会打印一个3,最后运行结束。

有了前面自己实现的 Observableof 的实现就会变得非常简单,它实际上只是 Observable 外套了一层包装,本质上还是 Observable,实现如下:

export function of(...args) {
   
  return new Observable(observer => {
   
    args.forEach(arg => {
   
      observer.next(arg);
    })
    observer.complete();
  })
}

把官方的 of 替换成自己的 of ,再配上自己实现的 Observable,我们会发现输出和官方一致。

3、Observable.subscribe 可以传人一个方法作为参数

官方 Observablesubscribe 可以传入一个函数进去,这样的话写起来会清爽很多,如下:

import {
    of } from 'rxjs';

const dataStream$ = of(1, 2, 3)

dataStream$.subscribe(console.log);

为了我们的 Observable 也能这样的好用,我们可以将 subscribe 适当的改造一下,如下:

export class Observable {
   
  _subscribe;
  constructor(subscribe) {
   
    this._subscribe = subscribe;
  }
  subscribe(observer) {
   
    const defaultObserver = {
   
      next: () => {
    },
      error: () => {
    },
      complete: () => {
    }
    }
    if (typeof observer === 'function') {
   
      return this._subscribe({
    ...defaultObserver, next: observer });
    } else {
   
      return this._subscribe({
    ...defaultObserver, ...observer });
    }
  }
}

这样我们的 subscribe 也能只传一个方法进去了,变得相当好用。

4、实现创建类操作符 fromEvent

但是,Rxjs 核心要解决的是数据流传输的问题,很多时候,我们的数据源头来自用户的人机交互,比如说点击按钮,这样的话就不得不用到 fromEvent,比如如下代码:

import {
    fromEvent } from 'rxjs';
import {
    JSDOM } from 'jsdom';

const element = new JSDOM(`<div>Hello world</div>`).window.document.querySelector('div');

const source$ = fromEvent(element, 'click');

source$.subscribe(console.log);

setTimeout(() => {
   
  element.click()
}, 1000)

为了方便对比和测试,我们引用了 jsdom,它的作用是在 node 端可以做一些 dom 的相关操作。

以上代码渲染了一个 Hello world 的元素盒子,并且在一秒钟之后会点击这个盒子。与此同时,我们又使用了 Rxjs 中的 fromEvent 来监听盒子的事件。

为了实现自己的fromEvent,我们来分析一下 fromEvent 所需要的参数,第一个传的是 dom 元素的实例,第二个则是事件的类型,于是可以猜到, fromEvent 内部本质上还是通过原生的 addEventListener 来实现的。而且需要注意到,除非自己手动取消订阅,否则fromEvent创造的对象永远不会结束,根据这个推测,我们能猜到它的内部很有可能只有 next 方法。

有了上述的推断,我们很容易就写出了一个 fromEvent 方法,如下:

export function fromEvent(element, event) {
   
  return new Observable(observer => {
   
    const handler = e => observer.next(e);
    element.addEventListener(event, handler);
  });
}

连我都惊讶它的实现居然如此简短,但是运行的效果和官方的效果完全一致。

5、实现创建类操作符 from、interval、timer

有了上面构造 offromEvent 的基础,那么 fromintervaltimer 也将不在话下。

例如,interval 操作符可以这样实现:

export function interval(delay) {
   
  return new Observable(observer => {
   
    let index = 0;
    setInterval((() => {
   
      observer.next(index++)
    }), delay)
  })
}

timer 操作符可以这样实现:

export function timer(delay) {
   
  return new Observable(observer => {
   
    setTimeout((() => {
   
      observer.next
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值