Rxjs初体验:制作语音测试工具
学习Rxjs是两个月前的事了,但没有用到在一个实际需求上。近日收到一个需求,正好是一个可以抽象为由数据流驱动的应用,于是我欣然用Rxjs结合React写之。
需求说明
需求原始说明为:
60个英文单词被分为三个组系,每个组系包括2-6个单词一组的五组单词。在测试中,测试单词以1词/秒的速率依次呈现在电脑屏幕上,被试大声朗读屏幕上的单词,当一组单词呈现结束时,屏幕上出现与该组数目相等的问号,提示被试用刚才呈现的单词造句。 两个一组时,屏幕上以1词/秒的速率依次出现“price”,“week”,两个单词后会出现??,受试用price造句,造完句后点下鼠标,屏幕上出现一个问号,受试用week造句,之后点鼠标进入三个一组,屏幕上以1词/秒的速率依次出现“bird”,“game”,“ star”,三个单词后会出现???,受试用bird造句,造完句后点下鼠标, 屏幕上出现两个问号,受试用game造句,再点下鼠标, 屏幕上出现一个问号,受试用star造句,之后点鼠标进入四个一组…以此类推。
全程录音,计算机记录受试每个单词造句所用时间。
需求原始说明可能有些不易看明,经过讨论,我归总如下:
数据格式为:(
word.组系序号.组单词数.组内序号
)Test1 Test2 Test3 word.1.2.1 word.2.2.1 word.3.2.1 word.1.2.2 word.2.2.2 word.3.2.2 word.1.3.1 word.2.3.1 word.3.3.1 word.1.3.2 word.2.3.2 word.3.3.2 word.1.3.3 word.2.3.3 word.3.3.3 ... ... ... word.1.6.6 word.2.6.6 word.3.6.6 由此,抽象为以下数据类型:
// 代表一个组系 interface TestItem {name: string; // 组系名,如:Test1, Test2, Test3/*二维数组表示的组系内数据项[word.1.2.1, word.1.2.2][word.1.3.1, word.1.3.2, word.1.3.3]...*/wordGroups: string[][]; } 复制代码
并将数据放入全局store:
class Store {// 组系items: TestItem[] = [];// 每组最小单词数minWordsCount = 2;// 每组最大单词数maxWordsCount = 6;// 实验开始前倒计时秒数countdown = 5; } 复制代码
流程:
倒计时
对每个组系:
对每一组:
- 依次显示单词,每个单词显示一秒
- 对每个单词:
- 显示
此组单词数 - i
个问号 - 如果
点击
事件发生,子流程结束
- 显示
- 子流程结束
子流程结束
流程结束
读者有意,可以试想一下普通做法如何实现。
数据流抽象
为了方便一些操作,我封装了一个
immediateInterval
,因为interval不是即时开始发射数据的:function immediateInterval(period?: number | undefined,scheduler?: SchedulerLike | undefined ): Observable<number> {return new Observable(subscriber => {subscriber.next(0);const interval$ = interval(period, scheduler);const next = subscriber.next; subscriber.next = function(this: Subscriber<number>, i: number) {next.bind(this)(i + 1);}.bind(subscriber);interval$.subscribe(subscriber);}); } 复制代码
由上节的流程,得到如下数据流:
倒计时:使用
immediateInterval
发出store.countdown
个值,每个值携带当前倒计时数,然后迭代
item of store.items
:迭代
group of item.wordGroups
:显示单词:使用
immediateInterval
发出group.length
个值,每个值携带当前单词,然后迭代
for(let i = 0; i < group.length; i++)
:- 发出值,携带
group.length - i
(问号数) - 订阅全局
event bus
的click
事件,当click
激发时,continue
此迭代
- 发出值,携带
数据流实现
以下代码的一些设计点:
- 使用
event bus
的emit
实现流程钩子,用来向外报告进行到了哪一步 - 使用
async await
语法实现异步迭代:async () => {for(...){await new Promise(async (resolve) => {someAsyncCode(// 结束此Promise,以continue该for循环resolve(); )})} } 复制代码
// event bus
const bus = new EventEmitter();const stream$ = new Observable<| { type: "倒计时"; count: number }| {type: "显示单词";word: string;}| {type: "显示问号";count: number;}
>(subscriber => {immediateInterval(1000).pipe(take(store.countdown + 1)).subscribe(i => {if (i !== store.countdown)subscriber.next({ type: "倒计时", count: store.countdown - i });},console.error,async () => {bus.emit("start", { type: "full" }); // 全程开始for (let item of store.items) {await new Promise(async (resolve, reject) => {bus.emit("start", { type: "item", item }); // 一组系开始for (let groupIndex = 0;groupIndex < item.wordGroups.length;groupIndex++) {const group = item.wordGroups[groupIndex];// 一组开始bus.emit("start", { type: "group", item, groupIndex }); // 一组开始await new Promise(async (resolve, reject) => {// 显示单词immediateInterval(1000).pipe(take(group.length)).subscribe(i => {subscriber.next({ type: "显示单词", word: group[i] });},console.error,() => {// 显示问号rxjs.timer(1000).subscribe(async () => {for (let i = group.length, wordIndex = 0;i > 0;i--, wordIndex++) {// 开始造句bus.emit("start", {type: "sentence",index: wordIndex,item,groupIndex});await new Promise(async (resolve, reject) => {subscriber.next({ type: "显示问号", count: i });const onClick = () => {resolve(); // next 问号bus.removeListener("click", onClick);};bus.addListener("click", onClick);});// 造句结束bus.emit("end", {type: "sentence",index: wordIndex,item,groupIndex});}resolve(); // next group});});});bus.emit("end", { type: "group", item, groupIndex }); // 一组结束}bus.emit("end", { type: "item", item }); // 一组系结束resolve(); // next test});}bus.emit("end", { type: "full" }); // 全程结束subscriber.complete();});
});
复制代码
连接到React组件(Hooks):
const Play = () => {const action = useObservable(() => stream$);let comp = null;if (!action) {comp = null;} else if (action.type === "倒计时") {comp = ...;} else if (action.type === "显示单词") {comp = ...;} else if (action.type === "显示问号") {comp = ...;}return ...;
};
复制代码
总结
Rxjs使得一些事情更容易(:
涉及到的一些库
rxjs
rxjs-hooks(rxjs与react hooks的结合库)
wolfy87-eventemitter(浏览器端的高效的EventEmitter)
转载于:https://juejin.im/post/5c54f00ef265da2de165761b
Rxjs初体验:制作语音测试工具相关推荐
- 体验Vs2005 beta2 测试工具
在Vs2005中加入了单元测试工具,使用与NUnit差不多.但功能更加丰富了,而且使用更加方便,有利于项目的协调工作.而且还支持调试测试,(不知道NUnit支不支持,我是没用过.)方便我们调试出错代码 ...
- memsql 落地mysql_MemSQL初体验 - (2)初始化测试环境
2.配置测试环境 创建一个用户,方便后续使用: MemSQL> grant all on *.* to jss identified by "jss" with grant ...
- MemSQL初体验 - (2)初始化测试环境
2.配置测试环境 创建一个用户,方便后续使用: MemSQL> grant all on *.* to jss identified by "jss" with grant ...
- NSIS 之初体验 制作打印机i5100windows安装程序
1.简介 NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows 系统下安装程序制作程序.它提供了安装.卸载.系统设置.文件解压缩等功能.这如其名 ...
- CentOS 初体验六:登录工具PuTTY使用
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78961584 本文出自[赵彦军的博客] PuTTY 简介 PuTTY是一个Teln ...
- 【第二趴】uni-app开发工具(手把手带你安装HBuilderX、搭建第一个多端项目初体验)
文章目录 写在前面 HBuilderX HBuilderX 优势 HBuilderX 安装 uni-app 初体验 写在最后 写在前面 聚沙成塔--每天进步一点点,大家好我是几何心凉,不难发现越来越多 ...
- FlashCache初体验
FlashCache初体验 注意: 测试用的是CentOS6.5 内核版本2.6.32-431.el6.x86_64 步骤: 上传CentOS6.5做本地yum源,安装以下包. yum install ...
- 【聆思CSK6视觉AI开发套件试用】CSK6系列头肩识别初体验
本篇文章来自极术社区与聆思科技组织的CSK6 视觉AI开发套件活动,更多开发板试用活动请关注极术社区网站.作者:張弩拔劍 背景 前言 聆思CSK4002以先进的AI算法, 出色的性价比, 以及优越的头 ...
- 腾讯内部测试软件,腾讯性能测试工具——PerfDog使用初体验
官网地址:https://perfdog.qq.com/ 使用说明:https://perfdog.qq.com/support 测试机型:锤子坚果pro2s (前几天得知我浩哥上了老赖名单,现在看着 ...
- OCR 工具tesseract初体验
OCR 工具tesseract初体验 @(工具使用)[工具使用, python] OCR即图片上文字识别 安装tesseract github地址 tesseract是一个命令行程序,后面安装的pyt ...
最新文章
- ERICA:提升预训练语言模型实体与关系理解的统一框架
- Windows中的命令行提示符里的Start命令执行路径包含空格时的问题
- NioEventLoop 的实例化过程
- 注解配置声明式事务控制解析
- 【ubuntu-qt-dlib】 配置问题 (二) terminate called after throwing an instance of 'dlib::image_load_error'
- node 版本升级_Node-RED: 自动化事件触发工具的安装与介绍
- php node.js django,Vue.js和Django搭建前后端分离项目示例详解
- django 1.8 官方文档翻译:7-2 管理操作
- 男性加入防晒大军 购买遮阳伞比例同比增长23.54%
- delphi idtcpclient 发送十六进制00_25656红单足球预测 中超 20:00 山东鲁能泰山 VS 大连人...
- [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)...
- 添加游戏到游戏浏览器中的小工具
- 别用Date了,Java8新特性之日期处理,现在学会也不迟!
- maven安装及配置
- 偏微分方程数值解的matlab程序,偏微分方程数值解法的MATLAB源码
- vue v-for循环表格 希望第四个<th>或<td>标签自动换到下一行应该怎么做?
- 如何在线下载哔哩哔哩上的视频
- 智能暖风机——8.云端控制
- Control Egress TCP Traffic
- async-profiler的使用与RocketMQ性能优化案例