RxJS结合vue-rx, Akita的介绍和使用
RxJS结合vue-rx, Akita的介绍和使用
RxJS结合vue-rx, Akita的介绍和使用介绍: 解决异步事件。它将一切数据包括HTTP请求,DOM事件或者普通数据等包装成流的形式,然后利用强大丰富的操作符(Operators )对流进行处理,使得用户可以用同步编程的方式处理异步数据。
基本概念:Observable 类似于函数声明,subscribe类似于函数调用,调用时传入回调函数Observable 对象来执行,执行后的返回值称为Subscription ,可以停止后续Observable 的执行
Observable (可观察对象): 。是一可观察序列,简单来说数据就在Observable中流动,用户可以使用各种operator对流进行处理。
//create方法创建一个Observable var observable = Observable .create(function(observer) { observer.next('Jerry'); observer.next('Anna'); }) // subscribe订阅 observable console.log('start'); observable.subscribe(function(value) { console.log(value); }) console.log('end'); // 输出 start Jerry Anna end
Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值,其包括以下三个方法
Next – 表示数据正常流动,没有出现异常
Error – 表示流中出错,可能是运行出错,http报错等
Complete – 表示流结束,不再发射新的数据
1、 要使用观察者,需要把它提供给Observable的subscribe方法。
2、 在一个流的生命周期中,error和complete只会触发其中一个,可以有多个next(表示多次发射数据),直到complete或者error。
console.log('just before subscribe'); const observe = { next: x => console.log('got value ' + x), error: err => console.error('something wrong occurred: ' + err), complete: () => console.log('done'), }; // 订阅这个 observable // 只有在订阅之后,才会在流Observable变化的时候,调用observer提供的方法,并通知它 observable.subscribe(observe); console.log('just after subscribe'); // 输出 just before subscribe got value 1 got value 2 got value 3 just after subscribe got value 4 done
Subscription (订阅): 表示 Observable 的执行,Subscription基本上只有一个unsubscribe()函数,这个函数用来释放资源或取消Observable执行,清理由Subscription占用的资源。
let subscription = observable.subscribe(observe); setTimeout(() => { subscription.unsubscribe(); }, 1000);
Operators (操作符):
操作符是Observable类型上的方法,用来处理集合。当操作符被调用时,它们不会改变已经存在的Observable实例。相反,它们会返回一个新的Observable,它的subscription逻辑基于第一个Observable。
其实部分操作符从功能来讲可能会觉得区别不太大,区分起来也比较困难,我们可以查阅它们的弹珠图来方便我们区分。
安装并配置vue-rx的依赖包
yarn add rxjs yarn add vue-rx //main.js文件 import VueRx from "vue-rx"; Vue.use(VueRx);
vue-rx会新增一个钩子函数subscriptions,和vue的data类似的使用;以及用来存放事件的一个domStreams数组
事件的使用:
<template> <ul> <li v-for="(num, index) in numList" :key="index" v-stream:click="{ subject: getNum$, data: { 'index': index, 'num': num } }">{{ num }}</li> </ul> <p>点击的数字为:{{ num$.index }}</p> <p>点击的数字下标为:{{ num$.num }}</p> </template> <script> import { Observable } from 'rxjs' export default { name: 'HelloWorld', data () { return { numList: [1, 2, 3] } }, domStreams: ['getNum$',], subscriptions() { return { num$: this.getNum$ // 从传入的对象中获取key为data的value,传入下一个operator .pluck('data') .map(data => data) // 因为视图引用了num$.index,所以这里要初始化num$为对象,避免报错 .startWith({}) } } </script>
关于switchMap、concatMap、exhaustMap的使用:
domStreams: ['getConcatMapCount$', 'getSwitchMapCount$', 'getExhaustMapCount$'], subscriptions() { return { // 当你连续点击按钮多次获取数据时,cancatMap会将获取到的数据按队列发出 concatMapCount$: this.getConcatMapCount$.concatMap(e => { return new Observable.from(this.getCount()); }), // 当你连续点击按钮多次获取数据时,switchMap只会将最后一个点击发出的值发出,前面发出的值会被吞掉 switchMapCount$: this.getSwitchMapCount$.switchMap(e => { return new Observable.from(this.getCount()); }), // 当你连续点击按钮多次时,exhaustMap仅执行一次,在第一次值发出后,才可以继续点击下一次发出值 exhaustMapCount$: this.getExhaustMapCount$.exhaustMap(e => { return new Observable.from(this.getCount()) }) } }, methods: { getCount() { return new Promise((resolve, reject) => { this.count ++; setTimeout(() => { resolve(this.count); }, 1000); }) } }
关于forkJoin的使用:
会在每个被合并的流都发出结束信号时发射一次数据,也就是只触发一次回调
methods: { getEmergencyMapData() { const $viewData = queryEmergencyViewMapData(this.$route.query.id).pipe( map(data => [data]), catchError(() => { return of([]); }) ); const $viewData2 = queryEmergencyIconpointMapData( this.$route.query.id ).pipe( map(data => [data]), catchError(() => { return of([]); }) ); const $viewData3 = queryEmergencyDecisionMapData( this.$route.query.id ).pipe( map(data => [data]), catchError(() => { return of([]); }) ); //同时发送三个请求,将返回值组成一个新的数组 forkJoin($viewData, $viewData2, $viewData3) .pipe( map(([view1, view2, view3]) => [...view1, ...view2, ...view3]) tap(data => { console.log(data ) }) ) .subscribe(); //在methods中必须订阅了才会发送请求 } }
Akita介绍: Akita是一种基于RxJS的状态管理模式,它采用Flux中的多个数据存储和Redux中的不可变更新的思想,以及流数据的概念,来创建可观察的数据存储模型。
安装并配置Akita的依赖包
yarn add @datorama/akita //main.js文件 import "./plugins/akita"; //akita.js文件 import { persistState } from "@datorama/akita"; import { akitaConfig } from "@datorama/akita"; if (process.env.NODE_ENV === "development") { import("@datorama/akita").then(modules => { modules.akitaDevtools(); }); } akitaConfig({ resettable: true }); persistState({ include: ["session"], storage: { getItem: key => sessionStorage.getItem(key), setItem: (key, value) => sessionStorage.setItem(key, JSON.stringify(value)), removeItem: key => sessionStorage.removeItem(key) } });
Akita的使用:
在src下新建store文件,目录结构如下
xxx.store.js: 存放所要管理的状态
import { createStore } from "@datorama/akita"; const initialState = { //存放ui展示的变量,一般为布尔值 UI: { isShowPlanPanel: false, //预案详情 }, //存放其他变量,字符串,数组,对象等 selectPlanId: null, //预案id }; export const basisDataStore = createStore(initialState, { name: "basisData" });
xxx.service.js: 操作store数据的方法的集合,比如对该数据的修改、增加、删除等等
import { basisDataStore } from "./basis-data.store"; export function isShowPlanPanel(show) { basisDataStore.update(state => ({ ...state, UI: { ...state.UI, isShowPlanPanel: show } })); } export function setSelectPlanId(id) { basisDataStore.update(state => ({ ...state, selectPlanId: id })); }
xxx.query.js: 将store数据暴露给外部,方便组件的调用
import { createQuery } from "@datorama/akita"; import { basisDataStore } from "./basis-data.store"; export const basisDataQuery = createQuery(basisDataStore); export const $isShowPlanPanel = basisDataQuery.select( state => state.UI.isShowPlanPanel ); export const $selectPlanId = basisDataQuery.select(state => state.selectPlanId);
参数传递的顺序依次是:
1.、组件A调用service.js的方法,为selectPlanId和isShowPlanPanel赋值
import { setSelectPlanId, isShowPlanPanel } from "../../store/basis-data/basis-data.service"; onClickRow(row) { isShowPlanPanel(true); setSelectPlanId(row.id); }
2、组件B在subscriptions钩子函数中监听selectPlanId和isShowPlanPanel的变化
import { $selectPlanId } from "../../store/basis-data/basis-data.query"; subscriptions() { return { isShowPlanPanel: $isShowPlanPanel, planData: $selectPlanId.pipe( mergeMap(planId => queryPlanDetails(planId )),//发送请求,获取详情 map(data => { if (data) { //数据处理 ... return data } }) ) }; },
RxJS结合vue-rx, Akita的介绍和使用相关教程
-
grain-Edu-Note part22 spring结合redis并使用友好的序列化方式
grain-Edu-Note part22 spring结合redis并使用友好的序列化方式 !-- spring boot redis 缓存引入-- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency !-- lecttuce 缓存连接池-- depend
-
C++核心准则T.5:结合使用泛型和面向对象技术应该增强它们的效果
C++核心准则T.5:结合使用泛型和面向对象技术应该增强它们的效果而不是成本 T.5: Combine generic and OO techniques to amplify their strengths, not their costs T.5:结合使用泛型和面向对象技术应该增强它们的效果而不是成本 Reason(原因) Generic and
-
源码分析-Condition结合AQS解析
源码分析-Condition结合AQS解析 Condition 如图,java.util.concurrent.locks包下,与AQS同级 主要方法就是 await() :使当前持有锁的线程进入等待 signal() : 唤醒等待的线程重新排队去抢锁 Condition常用于生产者消费者场景, 负责生产者消费者的阻塞用途 不
-
多线程结合线程池方式对文件批量下载到本地和压缩文件到浏览器
多线程结合线程池方式对文件批量下载到本地和压缩文件到浏览器 1.批量下载到本地: 首先先了解Executorsc创建的4中线程池的使用: 1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 2
-
结合namespace自己搭建MVC框架
结合namespace自己搭建MVC框架 结合namespace自己搭建MVC框架 MVC基本介绍 MVC是这3个单词的缩写: Model:模型,专门用来处理数据的 View:视图,专门用来显示内容(保存一些html文件) Controller:控制器(中控器),用来分发任务 (命令模型处理数据、命
-
docker,jenkins与ansible结合实践
docker,jenkins与ansible结合实践 1. 安装依赖 [[emailprotected] ~]# rpm -ivh /home/allen/container-selinux-2.107-3.el7.noarch.rpm[[emailprotected] ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 2. 下载docker ce的repo [[email
-
Zabbix结合Mojo-Webqq实现告警
Zabbix结合Mojo-Webqq实现告警 2019独角兽企业重金招聘Python工程师标准 重要通知 WebQQ已于2019年1月1日停止服务,Mojo-Webqq项目已停止维护。 安装方法 推荐使用cpanm在线安装或升级Mojo::Webqq模块, 如果使用docker方式请参见Docker镜像安装及使用方法 1.
-
复古与现代的完美结合本田 Honda CB650R
复古与现代的完美结合:本田 Honda CB650R 本田 Honda CB650R 排量:649 mL 发动机:水冷四冲程 并列四缸 长x宽x高:2140x750x1150 mm 最大功率:56/9000 kW(r/min) 最大扭矩:60/8000 Nm(r/min) 最高车速: 启动方式:电启动 点火方式:电喷 制动方式:前双