RxJS笔记

RxJS

《深入浅出RxJS》读书笔记

遗留问题

  1. Observable的HOT与COLD对应的实际场景,以及在编码中的体现

chapter1

html部分

测试你对时间的感觉按住我一秒钟然后松手你的时间:毫秒
  1. jquery实现

    var time = new Date().getTime();
    $("#hold-me").mousedown(function(event) {time = new Date().getTime();}).mouseup(function(event) {if (time) {var elapse = new Date().getTime() - time;$("#hold-time").text(elapse);// 重置time 避免直接触发mouseup事件,例如在A处点击然后在B处uptime = null;}});
  2. RxJS实现

    const holdMeButton = document.getElementById("hold-me");const mouseDown$ = Rx.Observable.fromEvent(holdMeButton,"mousedown");const mouseUp$ = Rx.Observable.fromEvent(holdMeButton,"mouseup");// 获取间隔时间const holdTime$ = mouseUp$.timestamp().withLatestFrom(mouseDown$.timestamp(),(mouseUpEvent,mouseDownEvent)=>{return mouseUpEvent.timestamp - mouseDownEvent.timestamp});holdTime$.subscribe(ms=>{document.getElementById("hold-time").innerText = ms;})holdTime$.flatMap(ms=>{return Rx.Observable.ajax('https://timing-sense-score-board.herokuapp.com/score/'+ms)}).map(e=>e.response).subscribe(res=>{document.getElementById("rank").innerText = `你超过了${res.rank}% 的用户`})

chapter2

Koa2的使用

主要用来加载静态资源,所以使用到了 koa,koa-static
const path = require("path");
const koa = require("koa");
const serve = require("koa-static");
const app = new koa();app.use(async function (ctx,next) {console.log("收到请求...")await next()console.log(`"${ctx.path}"请求 已处理...`)
})app.use(serve(path.resolve(__dirname, "../src"))).listen(3001,function(err){if(err) throw err;console.log("程序启动成功")
});

ObservableObserver

Observable 可被观察的对象,Observer观察者,Observer通过subscribe来观察Observable对象

RxJS的数据流就是Observable对象:

  1. 观察者模式
  2. 迭代器模式

举个栗子

// 使用 deep-link方式引入函数
const Observable = require("rxjs").Observable;/** 定义Observable对象的行为,会产生数据,调用订阅者的next方法* 1. 此处的Observer与订阅者行为 theObserver并不是同一个对象,而是对theObserver的包装* 2. 如果observer.error被调用,之后的complete或者next就不会被调用啦,同理,complete被调用之后,也不会*    再调用next或者error* 3. 如果error或者complete一直未调用,则observer就一直在内存中等待被调用
*/
const onSubscribe = observer =>{observer.next(1);observer.error(2);observer.complete(3);
}
// 产生一个Observable对象
const source$ = new Observable(onSubscribe);
// 定义观察者的行为 消费Observable对象产生的数据
const theObserver = {next:item => console.log(item),error:item => console.error(item),complete:item => console.log("已完成"),
}
// 建立Observable与Observer的关系
source$.subscribe(theObserver)

退订subscribe

在订阅一段事件之后observer不再响应吐出的信息了,这时可以退订,但是Observeable还会一直产生数据
const Observable = require("rxjs").Observable;const onSubscribe = observer =>{let n = 1;const handle = setInterval(()=>{console.log(`in onSubscribe ${n}`)// if(n>3){//     observer.complete()// }observer.next(n++);},1000)return {unsubscribe(){// clearInterval(handle)}}
}const source$ = new Observable(onSubscribe);const theObserver = {next:item => console.log(item)
}let subscription = source$.subscribe(theObserver)setTimeout(()=>{// 此处的unsubscribe也是封装过的subscription.unsubscribe()
},3500)

node中执行,会一直打印 in onSubscribe *,但是source$不会再响应

Chapter3 操作符基础

const Observable = require("rxjs/Observable").Observable;
const of = require("rxjs/observable/of").of;
const map = require("rxjs/operator/map").map;
// 新建一个操作符
// 此处this是外部变量,导致此operator不再是纯函数
Observable.prototype.double = function(){// return this::map(x=>x*2)return map.call(this,x=>x*2)
}const source$ = of(1,3,4);
const result$ = source$.double();result$.subscribe(value=>console.log(value))

lettable/pipeable操作符

解决需要使用call或者bind改变this的操作,这样是依赖外部环境的,不属于纯函数,也会丧失TS的类型检查优势
  • lettableObservable对象传递给下文,避免使用this

    const Observable = require("rxjs/Observable").Observable;
    require("rxjs/add/observable/of").of;
    require("rxjs/add/operator/map").map;
    require("rxjs/add/operator/let").let;const source$ = Observable.of(1,2,3);
    const double$ = obs$ => obs$.map(v=>v*2);
    // 接受上文,传递到下文
    const result$ = source$.let(double$);result$.subscribe(console.log)
    
不引入`map`补丁,开发**lettable**写法的操作符

// ES5实现
function map(project){

return function(obj$){// 通过上面的Observable生成一个新Observablereturn new Observable(observer=>{return obj$.subscribe({next:value=>observer.next(project(value)),error:err=>observer.error(err),complete:()=>observer.complete()})})
}

}
// 添加操作符
var result$ = source$.let(map(x => x * 3));

// ES6实现
const map6 = fn => obj$ =>

  new Observable(observer =>obj$.subscribe({next: value => observer.next(fn(value)),error: err => observer.error(err),complete: () => observer.complete()}));

// 添加操作符
var result$ = source$.let(map6(x => x * 4));


`pipeable`是`lettable`的别称,方便对于`lattable`的理解,V6以上才支持## Chapter4 创建数据流> 大多数的操作符是静态操作符### 基础操作符1.  `create`简单的返回一个Observable对象
Observable.create = function(subscribe){return new Observable(subscribe)
}
```
  1. of列举数据

    import {Observable} from "rxjs/Observable";
    import "rxjs/add/observable/of"
    // 依次吐出数据,一次性emit
    const source$ = Observable.of(1,2,3);
    // 订阅
    // 第一个参数是next,第二个参数是error回调,第三个参数是complete回调
    source$.subscribe(console.log,null,()=>{console.log("Complete")})
  2. range产生指定范围的数据

    const sourc$ = Observable.range(/*初始值*/1,/*个数*/100);
    // 每次只能步进 1
  3. generate循环创建

    相当于for循环
    const source$ = Observable.generate(// 初始值2,// 判断条件value=> value < 10,// 步进value=> value+0.5,// 函数体,产生的结果value=> value*value
    )

    使用generate代替range

    const range = function(min,count){const max = min + count;return Observable.generate(min,v=>vv+1,v=>v*v)
    }
  4. repeat重复数据的数据流

    实例操作符,通过import 'rxjs/add/operator/repeat'引入

    1. V4版本中repeat是静态属性,这样在使用Observable.repeat(1,2)重复1两次,这样数据就够灵活
    2. V5版本中改为实例属性之后,Observable.of(1,2,4).repeat(2),将产生的1,2,3重复两次,功能更加强大
    const Observable = require("rxjs").Observable;
    require("rxjs/add/operator/repeat");const source$ = Observable.create(observer => {setTimeout(() => {observer.next(1);}, 1000);setTimeout(() => {observer.next(2);}, 2000);setTimeout(() => {observer.next(3);}, 3000);setTimeout(() => {observer.complete(1);}, 4000);return {unsubscribe(){console.log("on Unsubscribe")}}
    });const repeat$ = source$.repeat(2)repeat$.subscribe(console.log,null,()=>{console.log("Complete")})// 1
    // 2
    // 3
    // on Unsubscribe
    // 1
    // 2
    // 3
    // Complete
    // on Unsubscribe
    • 如果没有observer.complete()repeat不会被调用

      repeat以complete为契机会再次执行数据源,如果上游一直没有complete下游就不会执行
    • 因为repeat的存在,第一次数据源执行完(以complete为契机)后并不会执行observer的complete回调
  5. empty,throw,never

创建异步数据的Observable对象

  1. intervaltimer

    interval类似于setInterval

    require('rxjs/add/observable/interval')
    // 每隔1000ms产生一个数据,初始值为0,步进为1
    Observable.interval(1000)'

    timer 是setTimeout的超集

    // 1000ms后开始产生数据,之后每隔1000ms产生一个数据,功能相当于interval
    Observable.timer(1000,1000)
    // 指定日期
    Observable.time(new Date(new Date().getTime() + 12000))
  2. from 把一切转化为Observable

    1. 将所有的Iterable的对象都转化为Observable对象
    2. 可以将Promise对象转化为Observable对象,功能与fromPromise相同
  3. fromPromise异步处理的对接

    const Observable = require("rxjs").Observable;
    require("rxjs/add/observable/fromPromise");const promise = Promise.resolve(123);
    Observable.fromPromise(promise).subscribe(console.log, null, () =>console.log("Complete")
    );
    //123
    //Complete
    const promise1 = Promise.reject("error");
    Observable.from(console.log,err => console.log("catch", err),() => console.log("Complete!")
    );
    // 未捕获的Promise错误
    // (node:765) UnhandledPromiseRejectionWarning: error
    // (node:765) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing
    // inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (
    // rejection id: 1)
    // (node:765) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
  4. fromEvent连接DOM与RxJS的桥梁

    const event$ = Observable.fromEvent(document.getElementById("btn"),"click");
    event$.subscribe(event=>{// Do something
    })

    在NodeJs中可以与EventEmitter交互

    const Observable = require("rxjs").Observable;
    const EventEmitter = require("events");
    require("rxjs/add/observable/fromEvent")const emitter = new EventEmitter();const source$ = Observable.fromEvent(emitter,"msg");
    source$.subscribe(console.log,null,()=>console.log("Complete"))emitter.emit("msg",1)
    // 1
    emitter.emit("msg","haha")
    // haha
    emitter.emit("a-msg","haha")
    //
    emitter.emit("msg",'nihao')
    // nihao

    fromEventHot Observable,也就是数据的产生和订阅无关,对于fromEvent来说,数据源是外部产生的,不受RxJS控制,这是Hot Observable对象的特点

  5. fromEventPattern针对不规范的事件源

    规范的事件源:DOM事件,EventEmitter事件
  6. ajax见最上面的例子
  7. repeatWhen

    例如 在上游事件结束之后的一段时间再重新订阅
    const Observable = require("rxjs").Observable;
    require("rxjs/add/operator/repeatWhen")const notifier = ()=>{return Observable.interval(1000);
    }const source$ = Observable.of(1,2,3);
    // const source$ = Observable.create(observer=>{
    //     observer.next(111);
    //     return {
    //         unsubscribe(){
    //             console.log("on Unsubscribe")
    //         }
    //     }
    // });
    const repeat$ = source$.repeatWhen(notifier);repeat$.subscribe(console.log,null,()=>console.log("Complete"))
    // 每隔一秒产生一次
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // 1
    // 2
    // 3
    // ^C
  8. defer延迟创建Observable

    针对Observable占用内存比较大的情况,懒加载
    const Observable = require("rxjs").Observable;
    require("rxjs/add/observable/defer");
    require("rxjs/add/observable/of");const observableFactory = ()=>Observable.of(1,2,3);
    const source$ = Observable.defer(observableFactory)

合并数据流

功能需求操作符
把多个数据流以首尾相连的方式合并 concat,concatAll
把多个数据流以先到先得的方式合并 merge,mergeAll
把多个数据流中的数据以一一对应的方式合并 zipzipAll
持续合并多个数据流中最新产生的数据 combineLatest,combineAll,withLatestFrom
从多个数据流中选取第一个产生内容的数据流race
在数据流前面添加一个指定数据startWith
只获取多个数据流最后产生的数据forkJoin
高阶数据流中切换数据源 switch,exhaust
  1. concat

    1. 实例方法
    2. 静态方法,如果两个数据没有先后关系,推荐使用此方法
    • 实例方法

      const Observable = require("rxjs").Observable;
      require("rxjs/add/operator/of")
      require("rxjs/add/operator/concat")const source$1 = Observable.of(1,2,3);
      const source$2 = Observable.of(4,5,6);source$1.concat(source$2).subscribe(console.log,null,()=>console.log("Complete"))
    • 静态方法

      const Observable = require("rxjs").Observable;
      require("rxjs/add/operator/of")
      require("rxjs/add/observable/concat")const source$1 = Observable.of(1,2,3);
      const source$2 = Observable.of(4,5,6);Observable.concat(source$1,source$2).subscribe(console.log,null,()=>console.log("Complete"))
`concat`在将上一个数据源传递下去的时候会调用上一个`Observable`的`unsubscribe`,如果上一个`Observable`一直为完结,后续的都不会被调用```javascript
const source$1 = Observable.internal(1000);
const source$2 = Observable.of(1);
const concated$ = Observable.concat(source$1,source$2);
// 此时 source$2永远不会被调用
```在此推测:`rxjs/add/operator/*`下的属性都是实例属性,`rxjs/add/observable/*`下的属性都是实例属性
  1. merge先到先得

    merge用在同步数据的情况下和concat表现只,不建议使用
    const Observable = require("rxjs").Observable;
    require("rxjs/add/operator/merge");
    require("rxjs/add/operator/map");
    require("rxjs/add/observable/timer");const source$1 = Observable.timer(0, 1000).map(x => x + "A");
    const source$2 = Observable.timer(500, 1000).map(x => x + "B");
    const source$3 = Observable.timer(1000, 1000).map(x => x + "C");// 此时 source$1与source$2永远不会停止,所以
    source$1.merge(source$2, source$3, /*此参数限制了合并的Observable的个数*/ 2).subscribe(console.log, null, () => console.log("Complete"));// 0A
    // 0B
    // 1A
    // 1B
    // 2A
    // 2B
    // 3A
    // 3B
    // 4A
    // 4B
    // ^C
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/390102.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

@hot热加载修饰器导致static静态属性丢失(已解决)

react开发的时候&#xff0c;引入热加载&#xff0c;用了修饰器的引入方式&#xff0c;发现了一个很有意思的问题&#xff0c;网上并没有相关文章&#xff0c;所以抛出来探讨下。 一段很简单的测试代码。但是经过babel编码后&#xff0c;变得很有意思。假设编码成es2016&#x…

学习vue.js的自我梳理笔记

基本语法格式&#xff1a; <script> new Vue({ el: #app, data: { url: http://www.runoob.com } }) </script> 指令 【指令是带有 v- 前缀的特殊属性。】 判断 <p v-if"seen">现在你看到我了</p> 参数 <a v-bind:href"url"&…

Spring+jpaNo transactional EntityManager available

2019独角兽企业重金招聘Python工程师标准>>> TransactionRequiredException: No transactional EntityManager availableEntityManager执行以下方法(refresh, persist, flush, joinTransaction, remove, merge) 都需要需要事务if (transactionRequiringMethods.cont…

01_Struts2概述及环境搭建

1.Struts2概述&#xff1a;Struts2是一个用来开发MVC应用程序的框架。Struts2提供了web应用程序开发过程中一些常见问题的解决方案;对用户输入的数据进行合法性验证统一的布局可扩展性国际化和本地化支持Ajax表单的重复提交文件的上传和下载... ...2.Struts2相对于Struts1的优势…

高可用性、负载均衡的mysql集群解决方案

2019独角兽企业重金招聘Python工程师标准>>> 一、为什么需要mysql集群&#xff1f; 一个庞大的分布式系统的性能瓶颈中&#xff0c;最脆弱的就是连接。连接有两个&#xff0c;一个是客户端与后端的连接&#xff0c;另一个是后端与数据库的连接。简单如图下两个蓝色框…

剥开比原看代码09:通过dashboard创建密钥时,前端的数据是如何传到后端的?

2019独角兽企业重金招聘Python工程师标准>>> 作者&#xff1a;freewind 比原项目仓库&#xff1a; Github地址&#xff1a;https://github.com/Bytom/bytom Gitee地址&#xff1a;https://gitee.com/BytomBlockchain/bytom 在前面一篇文章&#xff0c;我们粗略的研究…

004. ES6之函数的扩展

2019独角兽企业重金招聘Python工程师标准>>> 1. 函数参数的默认值 ES6 允许为函数的参数设置默认值&#xff0c; function log(x, y World) {console.log(x, y); }log(Hello) // Hello World log(Hello, China) // Hello China log(Hello, ) // Hello// 1. 参数变量…

一名3年工作经验的程序员应该具备的技能

本文转自:https://m.imooc.com/article/details?article_id7557 前言 因为和同事有约定再加上LZ自己也喜欢做完一件事之后进行总结&#xff0c;因此有了这篇文章。这篇文章大部分内容都是面向整个程序员群体的&#xff0c;当然因为LZ本身是做Java开发的&#xff0c;因此有一部…

多语言版希尔排序

2019独角兽企业重金招聘Python工程师标准>>> 简介 希尔排序(Shells Sort)是插入排序的一种又称“缩小增量排序”&#xff08;Diminishing Increment Sort&#xff09;&#xff0c;是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L…

UML 中extend和include的区别

在UML用例图中有两种关系——包含和扩展&#xff0c;容易混淆&#xff0c;下面通过一张表来区别一下这两种关系。 转载于:https://www.cnblogs.com/yonyong/p/8555547.html

浏览器兼容CSS渐进增强 VS 优雅降级如何选择

由于低级浏览器不支持 CSS3&#xff0c;但是 CSS3 特效太优秀不忍放弃&#xff0c;所以在高级浏览器中使用CSS3&#xff0c;而在低级浏览器只保证最基本的功能。二者的目的都是关注不同浏览器下的不同体验&#xff0c;但是它们侧重点不同&#xff0c;所以导致了工作流程上的不同…

2018年,牛客网小白月赛5

第一次啊&#xff0c;补题&#xff0c;希望大佬批评。 题目按我补题顺序来的。 https://www.nowcoder.com/acm/contest/135#question H 题 最大公倍数 题意:给出两个数&#xff0c;求最大公倍数 欧几里德算法算出最大公约数k; 然后算出。最大公倍数即可 代码如下&#xff1a; …

爬虫笔记(十二)——浏览器伪装技术

为什么要进行浏览器伪装技术&#xff1f; 有一些网站为了避免爬虫的恶意访问&#xff0c;会设置一些反爬虫机制&#xff0c;对方服务器会对爬虫进行屏蔽。常见的饭爬虫机制主要有下面几个&#xff1a; 1. 通过分析用户请求的Headers信息进行反爬虫 2. 通过检测用户行为进行反…

《活出生命的意义》:人生有何意义?

在你一生的阅读体验中&#xff0c;如果能够有一本书&#xff0c;它的某个章节、某种思想、或者某句话能够触动你的内心&#xff0c;解决你的困惑&#xff0c;甚至能改变你的命运&#xff0c;那这样的一本书你一定要视如珍宝&#xff0c;经常翻阅&#xff0c;维克多弗兰克尔的《…

右键添加git-bash

主要&#xff1a; 右键如果没有git-bash&#xff0c;如何给右键手动添加 前面对右键存在git-bash但使用出现问题的解决&#xff0c;也想到如果右键都没有&#xff0c;该如何给右键添加了&#xff0c;于是接着记录下如何添加的过程&#xff1a; 情形&#xff1a; 手动给右键添加…

Weblogic的缓存

2019独角兽企业重金招聘Python工程师标准>>> 最近遇到一个关于weblogic缓存的问题。再把war包放入到weblogic指定目录启动以后&#xff0c;访问页面信息没有更新。最后发现是\weblogic\user_projects\domains\base_domain\servers\AdminServer下的文件没有清除&…

725. 分隔链表

725. 分隔链表 给你一个头结点为 head 的单链表和一个整数 k &#xff0c;请你设计一个算法将链表分隔为 k 个连续的部分。 每部分的长度应该尽可能的相等&#xff1a;任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。 这 k 个部分应该按照在链表中出现的顺…

LAMP介绍-MySQL安装

2019独角兽企业重金招聘Python工程师标准>>> LAMP: linux-apache-mysql-php &#xff08;安装方式有&#xff1a;rpm&#xff0c;源码&#xff0c;二进制免编译&#xff09; linux-操作系统 apache-web服务软件&#xff08;httpd&#xff09; mysql-存储数据库 php…

java1

不知道为啥粘贴的图片是一堆编码。。。。 如何插入图片 博客后后台MarkDown编辑器上只有一个按钮&#xff0c;就是用来上传图片并自动插入MarkDown标记的&#xff0c;超级好用 &#xff08;一&#xff09;学习总结 1.在java中通过Scanner类完成控制台的输入&#xff0c;查阅JDK…

430. 扁平化多级双向链表

430. 扁平化多级双向链表 多级双向链表中&#xff0c;除了指向下一个节点和前一个节点指针之外&#xff0c;它还有一个子链表指针&#xff0c;可能指向单独的双向链表。这些子列表也可能会有一个或多个自己的子项&#xff0c;依此类推&#xff0c;生成多级数据结构&#xff0c…