最近因为一个偶然的机会接触到了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
,因为楼主读书少也不懂那些什么观察者订阅者模式, 我这里就直接大白话解释就是,调用stream
的subscribe
可以订阅其,每当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