ReactiveX 结合了 观察者模式、迭代器模式 和 使用集合的函数式编程,以满足以一种理想方式来管理事件序列所需要的一切。
为什么要学习Rxjs呢?
因为它是Promise 的超集;
Promise 有一个缺点,那便是一旦调用了resolve或者是reject之后便返回了. 不能再次使用resolve 或者是reject ; 想象一下, 若是从端口源源不断地发出消息;每次收到的消息就要通知.回掉函数来处理, 那该怎么办呢?
于是 , 伟大的Rx 就有出现了 ~
还有在angular4+ 的开发中, Rxjs 是必学的;
在 RxJS 中用来解决异步事件管理的的基本概念是:
Observable
(可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。
Observer
(观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
Subscription
(订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
Operators
(操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
Subject
(主体): 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
Schedulers
(调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他。
在工作区里面建立简单的html 页面
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Rx学习title>
head>
<body>
<input type="text">
<div id="result">div>
body>
<script src="https://cdn.bootcss.com/rxjs/6.0.0-alpha.3/Rx.min.js">script>
html>
/**
* 这里把foo 看成一个函数,意味着每次调用foo 时都回导致传入Rx.Observable.create里的回调重新执行一次,
* @type {Observable|*}
*/
let foo = Rx.Observable.create(observer => {
console.log("hello")
// observer.next表示一个返回值,当然可以多次调;
// 每次调用后会将next里面的值返回给 foo.subscribe里面的回掉,执行完后再返回
observer.next(42)
});
//foo.subscribe调用方法相当与foo(); 为了通过里面的回掉函数来获取值;
foo.subscribe(x => console.log(x))
foo.subscribe(y => console.log(y))
// Observable里面怎么控制流的 ?
var observable = Rx.Observable.create(observer => {
try {
observer.next(1)
observer.next("hello")
observer.next(2)
observer.next(3)
// 到这步就完成了. 面的next 就不会执行了
observer.complete();
observer.next(4)
} catch (err) {
observer.error(err)
}
})
// 这么看observable.subscribe 怎么封装的callback
var observer = {
next(value) {
console.log(value)
},
complete() {
console.log('完成')
},
error(err) {
console.log(value)
}
}
let subcription = observable.subscribe(observer)
// Rx.Observable.interval可以返回一个能够发射(返回123的数字) 间隔时1000毫秒
var observable = Rx.Observable.interval(1000);
var subscription = observable.subscribe(x => console.log(x));
setTimeout(()=>{
//subscription里面的有个方法 unsubscribe可以取消订阅observable里发射的数据
// 但是Observable仍然在吐数字
subscription.unsubscribe();
},3000)
// Subject是一种能够发射多个数据给observer的Observable, 看起来好像是EventEmintter
var subject=new Rx.Subject();
subject.subscribe({
next:(v=>{console.log("a:"+v)})
});
subject.subscribe({
next:(v=>{console.log("b:"+v)})
})
subject.next(1)
subject.next(2)
// 与Observable不同的是, Subject发射数据给多个observer. 其次,定义subject时没有传入callback;
// 是因为subject 它自带next ,complete ,error 等方法;从而可以发射数据给observer,
// observer不知道数据是 Observable 还是subject给的数据;透明的;
// 而且,subject有各种派生
// BehaviorSubject能够保留最近的数据,使得当有subscribe的时候,立马能发射出去
// ReplaySubject 能够保留最近的一些数据, 使得当有subscript的时候,将这些数据发射出去
// AsyncSubject 只会发射结束前的一个数据
// Multicasted Observables 是一种借助Subject来讲数据发射给多个observer的Observable
var a,b=1,c=2;
a=b+c;
console.log("b=" + b);
console.log("c=" + c);
console.log("a=" + a);
b=3;
c=2;
console.log("a=" + a);
// 在传统编程中 a 的值不会随着bc变
// 那么在响应式编程中的怎么实现呢?
/*
* 1,操作符 : from zip等.. Rx里面有太多着这样的操作符:创建类,变换类,过滤类,合并类,处理错误类,工具类,数学类等等
* 2,lamda表达式 =>: 可以把他想成一个数据的指向,左边获取数据,右边处理输出数据;
* */
//为什么规范性 "b$" 命名呢? 加了$ 说明是一个流操作;
var b$=Rx.Observable.from([1,3]);
var c$=Rx.Observable.from([2,2]);
var a$=Rx.Observable.zip(b$,c$,(b,c)=>{
console.log("b=" + b);
console.log("c=" + c);
return b+c;
})
a$.subscribe(a=>{console.log("a=" + a);})
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Rx再体验title>
<script src="https://code.jquery.com/jquery-3.1.0.js">script>
<script src="https://cdn.bootcss.com/rxjs/6.0.0-alpha.3/Rx.min.js">script>
head>
<body>
<input type="text" name="" id="todo">
<button id="addBtn">addbutton>
<script>
//一般Rxjs里面一边在Observable类型的变量后面加了$标识,这就是一个流变量,预定熟成的
//显示获取todo输入框对象, 然后定义一个观察者对象,将todo的keyup事件转化成一个数据流,
// 然后订阅这个数据流再input 中显示
// filter 过滤器
// map 允许对数据流每个元素进行函数,
//map使用的场景太多. rx团队准们搞出了 pluck 操作符;从事一系列嵌套属性中把值提取出来形成新的流.
let todo = document.getElementById('todo');
let input$ = Rx.Observable.fromEvent(todo, 'keyup');
// input$
// .filter(ev => ev.keyCode == 32)
// .map(ev=>ev.target.value*10)
// .pluck('target', 'value')
// .subscribe(value => console.log(value.target.value))
//from操作符:可以支持数组,类数组的对象. promise iterable对象或类似Observable的对象
// 这个操作符应该是可以创建Observable的操作符中最常用的一个.几乎可以把任何对象换成Observable.
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)
.map(event => event.clientX)
.scan((count, clientX) => count + clientX, 0)
.subscribe(count => console.log(count));
script>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Rx学习title>
head>
<body>
<h4>我们做一个简单的BMI 公式h4>
weight:
<input type="number" id="weight">kg
<br>
height:
<input type="number" id="height"> cm
<br>
Your BMI is
<div id="bmi">div>
body>
<script src="https://cdn.bootcss.com/rxjs/6.0.0-alpha.3/Rx.min.js">script>
<script>
let weight = document.getElementById('weight');
let height = document.getElementById('height');
let bmi = document.getElementById('bmi');
let weight$ = Rx.Observable.fromEvent(weight, 'input')
.pluck('target', 'value')
let height$ = Rx.Observable.fromEvent(height, 'input')
.pluck('target', 'value')
let bmi$ = Rx.Observable.combineLatest(weight$, height$, (w, h) => w / (h * h / 100 / 100))
bmi$.subscribe(b => bmi.innerHTML = b)
//这里combineLatest的逻辑不要太湿滑,
//combineLatest和zip不一样;
script>
html>
这里推荐学习文档: https://ithelp.ithome.com.tw/users/20103367/articles
官网: https://cn.rx.js.org/manual/overview.html#-