初识rxjs

最近因为一个偶然的机会接触到了rxjs, 但是发现网上关于rxjs的教程偏少,并且就我而言看了许多篇文章也只能算是踏进了rxjs的大门,所以我想在这里整理一下我的学习笔记,帮助各位想要学习rxjs的童鞋避免采坑

由于楼主对于rxjs的理解也只能算是入门,如果有什么不对的地方还请各位大佬不吝赐教

首先按照我学习一个框架的思路,我会要首先知道rxjs是什么?解决了什么问题?

  • rxjs是什么?
    根据楼主的理解以及结合官方文档来看rxjs是一个怎么说呢?算是简化js异步操作的一个库

  • rxjs解决了什么问题?
    按照楼主现阶段对于rxjs的学习,rxjs本身是一个响应式编程js库,而我们前端经常写的react, vue呢实际上也是封装了响应式系统(数据改变触发视图更新嘛),所以rxjs主要是用来解决复杂的异步操作,让其更简单。

楼主可能解释的不好,下面主要会给出实际操作,让各位清楚的知道rxjs的厉害之处

众所周知如今的前端可以说是到处都遍布着异步操作,得益于js的单线程机制,所以我们每天写代码都需要处理许许多多的异步操作,什么定时器啊,事件啊, promise啊等等都是异步,也都可以被rxjs所操作

首先我们先简单的认识一下rxjs吧,就用它来处理一下我们常见的事件吧,在此之前请各位看官记住一句话,rxjs中所有的异步操作都称之为stream,当然官方称之为Observable

举个栗子:
比如说我们需要在document上注册一个mousemove事件, 这时候我们需要这样写

document.addEventListener('mousemove', (evt) => {
      // 就打印一下光标距离页面的Y轴坐标吧
      console.log(evt.pageY)
})

好的,那现在需求升级,我们需要限制一下这个函数所执行的次数,就是节流。相信这个逻辑对于已经入职写前端的童鞋非常常见吧,如果我们用原生实现的话

 let throttleTimer = null
    let throttleInterval = 2000
    document.addEventListener('mousemove', (evt) => {
      if (!throttleTimer) {
        throttleTimer = setTimeout(() => {
          // 就打印一下光标距离页面的Y轴坐标吧
          console.log(evt.pageY)
          throttleTimer = null
        }, throttleInterval)
      }  
})

这样我们就实现了2s之内无论触发了多少事件都只会执行一次我们的事件处理函数,当然节流这个需求在resize等事件是特别需要的

我们在进阶一下这个需求吧,要求鼠标在document上面移动的时候会有一个元素跟着它走,这时候我们又应该怎么用原生实现呢?下面贴出简单代码

有没有觉得有点复杂啊, 接下来我们看看rxjs是如何实现上面这一堆代码的吧

首先rxjs有一个方法可以将异步操作转换为stream(observable我这里就同一叫stream了)

import { fromEvent } from 'rxjs'
const event$ = fromEvent(document, 'mousemove')

这里的变量名后缀加$用来区分其是一个stream,然后rxjs是一个响应式编程库吗,所以我们只需要操作这个stream就行了,比如我们需要让stream节流17ms我们可以这样

import { fromEvent } from 'rxjs'
import { throttleTime } from 'rxjs/operators'
const event$ = fromEvent(document, 'mousemove')
event$.pipe(throttleTime(17))

rxjs/operators这个库是一些rxjs用来提供操作stream的一些操作符, 比如上面我们通过throttleTime控制stream每隔17ms触发一次
(这里相信聪明的童鞋已经知道为什么我更愿意称之为stream了,各位应该发现了操作符是通过一个叫pipe的函数操作stream的,这种类似于管道的机制,操作对象不就是stream吗)
大家这里也要明白rxjs的哲学(我理解的),通过操作符操作转换限制stream(视需求而定)得到我们想要的stream然后执行副作用代码

这里我们可以分析需求,我们需要得到stream之中所包含的光标位置信息,我们第一件事就是操作符,所以rxjs这个网站你一定是经常看的,这里我们需要一个叫做map的操作符, 这个操作符就像列表的map方法一样将一个stream转换为另一个stream

试试吧

import { fromEvent } from 'rxjs'
import { throttleTime, map } from 'rxjs/operators'
const event$ = fromEvent(document, 'mousemove')
event$.pipe(throttleTime(17),  map((evt: MouseEvent) => [evt.clientX, evt.clientY]))

我们可以使用pipe赋予多个操作符,每个操作符会按照参数顺序从左到右依次执行。这里我们使用了一个map的操作符,这个操作符接收前一个stream所携带的数据作为参数(如果有),这里前一个stream携带的很明显就是event对象啦,而这个操作符将前一个stream所携带的数据进行了过滤,在这里是拿到了我们需要的光标位置信息然后作为一个列表返回了,这个列表在这里就是我们源stream经过操作符转换得到的最终stream所携带的数据

这时候我们就有一个疑问了,我们已经通过操作转换stream的方式得到了我们想要的stream那么我们怎么执行副作用代码呢?光拿到我们需要的数据不够啊,这时候我们就需要stream为我们提供的第二个函数了subscribe,因为楼主读书少也不懂那些什么观察者订阅者模式, 我这里就直接大白话解释就是,调用streamsubscribe可以订阅其,每当stream被触发并且经过操作转换生成最终(如果没有被打断)的stream时会调用传入subscribe函数的参数(subscribe函数接收一个执行副作用代码的函数作为参数)

这样我们就可以完成我们上面的业务了

    const element = document.createElement('div')
    element.style.position = 'fixed'
    element.style.width = '100px'
    element.style.height = '100px'
    element.style.border = '1px solid red'
    document.body.appendChild(element)
    const event$ = fromEvent(document, 'mousemove')
    event$
      .pipe(
        throttleTime(17),
        map((evt: MouseEvent) => [evt.clientX, evt.clientY])
      )
      .subscribe(([x, y]) => {
        element.style.top = y + 'px'
        element.style.left = x + 'px'
 })

我们在进行分析一下上面的代码干了啥吧
首先使用fromEvent函数将元素事件转换成了stream

然后通过pipe赋予了两个操作符,第一个操作符限制stream只能每隔17ms触发一次

第二个操作符将stream所携带的数据进行了过滤得到了我们想要的数据,然后作为返回值由最终stream携带

然后我们调用了subscribe订阅了stream的触发,每一次stream最终触发就会执行传入subscribe函数的副作用代码,可以执行任何副作用操作

好了这就是rxjs目前我所能够掌握的那些了
这里还请大家铭记,rxjs通过将异步操作或者一些数据转换为stream然后通过操作符过滤限制甚至可以中断stream(根据实际需求)达成我们需要的效果

这里可能叫操作符不是那么好,但是我也确实不知道应该怎么叫了,后面我还会继续更新此文章。。。

谢谢各位看官捧场, 喜欢的麻烦点个赞加个关注啊。

last update: 2021年03月08日17:38:54

你可能感兴趣的:(初识rxjs)