为什么要使用 RxJS
RxJS 是一套处理异步编程的 API,那么我将从异步讲起。
前端编程中的异步有:事件(event)、AJAX、动画(animation)、定时器(timer)。
异步常见的问题回调地狱(Callback Hell)
竞态条件(Race Condition)
内存泄漏(Memory Leak)
管理复杂状态(Manage Complex States)
错误处理(Exception Handling)
回调地狱就是指层层嵌套的回调函数,造成代码难以理解,并且难以协调组织复杂的操作。
竞态条件出现的原因是无法保证异步操作的完成会和他们开始时的顺序一样,因此最终结果不可控。比如常见的 AutoComplete 效果,每次输入后向后端发送请求获取结果展示在搜索框下面,由于网络、后端数据查询等原因有可能出现最后发送的请求比之前的请求更快地完成了,这时最终展现的并不是最后那个请求的结果,而这并不是我们所希望的。
这里说的内存泄漏指的是单页应用切换页面时由于忘记在合适的时机移除监听事件造成的内存泄漏。
异步带来了状态的改变,可能会使状态管理变得非常复杂,尤其是某个状态有多个来源时,比如有些应用,一开始有一个默认值,再通过 AJAX 获取初始状态,存储在 localStorage,之后通过 WebSocket 获取更新。这时查询状态可能是同步或者异步的,状态的变更可能是主动获取也可能是被动推送的,如果还有各种排序、筛选,状态管理将会更加复杂。
JavaScript 中的 try/catch 只能捕获同步的错误,异步的错误不易处理。
Promise使用 Promise 可以减轻一些异步问题,如将回调函数变为串行的链式调用,统一同步和异步代码等,async/await 中也可以使用 try/catch 来捕获错误。但是对于复杂的场景,仍然难于处理。而且 Promise 还有其他的问题,一是只有一个结果,二是不可以取消。
异步 API:异步编程时不仅要面对这些问题,还有下面这些使用方式各异的 API:
DOM Events
XMLHttpRequest
fetch
WebSocket
Service Worker
setTimeout
setInterval
requestAnimationFrame
而如果使用 RxJS,可以用统一的 API 来进行处理,而且借助 RxJS 各种强大的操作符,我们可以更简单地实现我们的需求。
认识 RxJS 什么是 RxJS我们都知道 JS 是什么,那么什么是 Rx 呢?Rx 是 Reactive Extension(也叫 ReactiveX)的简称,指的是实践响应式编程的一套工具,Rx 官网首页的介绍是一套通过可监听流来做异步编程的 API(An API for asynchronous programming with observable streams)。
Rx 最早是由微软开发的 LinQ 扩展出来的开源项目,之后由开源社区维护,有多种语言的实现,如 Java 的 RxJava,Python 的 RxPY 等,而 RxJS 就是 Rx 的 JavaScript 语言实现。
RxJS 的两种编程思想RxJS 引入了两种重要的编程思想:函数式编程和响应式编程。
函数式编程(Functional Programming,简称 FP)是一种编程范式,强调使用函数来思考问题、编写代码。
In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.
函数式编程的主要设计点在于避免使用状态和可变的数据,即 stateless and immutable。
函数式编程对函数的使用有一些特殊要求:
声明式(Declarative)
纯函数(Pure Function)
数据不可变性(Immutability)
声明式的函数,让开发者只需要表达”想要做什么”,而不需要表达“怎么去做”。
纯函数指的是执行结果由输入参数决定,参数相同时结果相同,不受其他数据影响,并且不会带来副作用(Side Effect)的函数。副作用指的是函数做了和本身运算返回值没有关系的事情,如修改外部变量或传入的参数对象,甚至是执行 console.log 都算是 Side Effect。前端中常见的副作用有发送 http 请求、操作 DOM、调用 alert 或者 confirm 函数等。满足纯函数的特性也叫做引用透明度(Referential Transparency)。
数据不可变就是指这个数据一旦产生,它的值就永远不会变。JavaScript 中字符串类型和数字类型就是不可改变的,而对象基本都是可变的,可能会带来各种副作用。现在有各种库可以实现 Immutable 特性,如 immutable.js 和 immer.js
中文维基上说响应式编程(Reactive Programming)是一种面向数据流(stream)和变化传播的编程范式。个人的理解是对数据流进行编程的一种编程范式,使用各种函数创建、组合、过滤数据流,然后通过监听这个数据流来响应它的变化。响应式编程抽象出了流这个概念,提高了代码的抽象级别,我们不用去关心大量的实现细节,而专注于对数据流的操作。