美文网首页
初识rxjs

初识rxjs

作者: 看物看雾 | 来源:发表于2021-03-08 17:39 被阅读0次

    最近因为一个偶然的机会接触到了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上面移动的时候会有一个元素跟着它走,这时候我们又应该怎么用原生实现呢?下面贴出简单代码

    <div
      style="width: 100px; height: 100px; border: 1px solid red; position: fixed; top: 0; left: 0"
    ></div>
    
    <script>
      const element = document.querySelector('div')
    
      let throttleTimer = null
      let throttleInterval = 17  // 这里之所以选择17秒,是因为我们大部分显示器的刷新频率都是60hz,所以一秒钟最多执行60次更新
      document.addEventListener('mousemove', (evt) => {
        if (!throttleTimer) {
          throttleTimer = setTimeout(() => {
            // 就打印一下光标距离页面的Y轴坐标吧
    
            element.style.left = evt.clientX + 'px'
            element.style.top = evt.clientY + 'px'
    
            throttleTimer = null
          }, throttleInterval)
        }
      })
    </script>
    
    

    有没有觉得有点复杂啊, 接下来我们看看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

          本文链接:https://www.haomeiwen.com/subject/mjmpqltx.html