当前位置: 首页 > news >正文

响应式编程html,函数式响应式编程 - Functional Reactive Programming-Go语言中文社区

我们略过概念,直接看函数式响应式编程解决了什么问题。

故事从下面这个例子展开:

两个密码输入框,一个提交按钮。

f4c969539483bcd35c49cb3bb6f63d06.png

密码、确认密码都填写并一致,允许提交;不一致提示错误。

HTML 如下:

提交

常规做法

初始版

const validate = () => {

const match = pwd.value === confirmPwd.value;

const canSubmit = pwd.value && match;

errorLabel.innerText = match ? "" : "密码不一致";

if (canSubmit) {

submitBtn.removeAttribute("disabled");

} else {

submitBtn.setAttribute("disabled", true);

}

};

pwd.addEventListener("input", validate);

confirmPwd.addEventListener("input", validate);

加强版

问题: 输入密码时,确认密码还是空的,出现密码不一致错误提示,干扰用户输入。

期望: 确认密码没输入过时,不提示错误。

为解决这个问题,用 isConfirmPwdTouched 标识确认密码输入框是否输入过内容。

let isConfirmPwdTouched = false;

pwd.addEventListener("input", () => {

if (isConfirmPwdTouched) validate();

});

confirmPwd.addEventListener("input", () => {

isConfirmPwdTouched = true;

validate();

});

测试同学又发现了一个 bug:

不输密码,直接输入确认密码,这时又出现了错误提示。

为解决这个问题,再加入一个标识位 isPwdTouched。

let isConfirmPwdTouched = false;

let isPwdTouched = false;

pwd.addEventListener("input", () => {

isPwdTouched = true;

if (isPwdTouched && isConfirmPwdTouched) validate();

});

confirmPwd.addEventListener("input", () => {

isConfirmPwdTouched = true;

if (isPwdTouched && isConfirmPwdTouched) validate();

});

旗舰版

问题: 确认密码输入框输入第一个字符时就会提示密码不一致,干扰用户输入。

期望: 连续输入时,不提示错误。

为解决这个问题,高级一点的做法是使用高阶函数 debounce,否则又要多个标识位。

const debounce = (fn, ms) => {

let timeoutId;

return (...args) => {

if (timeoutId !== undefined) clearTimeout(timeoutId);

timeoutId = setTimeout(fn.bind(null, ...args), ms);

};

};

const validate = () => {

const match = pwd.value === confirmPwd.value;

const canSubmit = pwd.value && match;

errorLabel.innerText = match ? "" : "密码不一致";

if (canSubmit) {

submitBtn.removeAttribute("disabled");

} else {

submitBtn.setAttribute("disabled", true);

}

};

const debouncedValidate = debounce(validate, 200);

let isConfirmPwdTouched = false;

let isPwdTouched = false;

pwd.addEventListener("input", () => {

isPwdTouched = true;

if (isPwdTouched && isConfirmPwdTouched) debouncedValidate();

});

confirmPwd.addEventListener("input", () => {

isConfirmPwdTouched = true;

if (isPwdTouched && isConfirmPwdTouched) debouncedValidate();

});

常规做法的问题

可以看出:随着交互越来越复杂,常规做法的标识位越来越多,代码的逻辑越来越难理清。

常规做法实际实现了下图的逻辑:

efd10cff878b36174b26037fbd33e03a.png

图看起来清晰易懂,但可惜的是 代码和这张图长得并不像。

有没有一种办法,让我们的代码和上图一样逻辑清晰呢?

答案就是:函数式响应式编程。

用它写代码就像是在画上面那张图。

函数式响应式做法

这里使用的库是rxjs。

const { fromEvent, combineLatest } = rxjs;

const { map, debounceTime } = rxjs.operators;

const pwd$ = fromEvent(pwd, "input").pipe(map(e => e.target.value));

const confirmPwd$ = fromEvent(confirmPwd, "input").pipe(

map(e => e.target.value)

);

combineLatest(pwd$, confirmPwd$)

.pipe(

debounceTime(200),

map(([pwd, confirmPwd]) => ({

match: pwd === confirmPwd,

canSubmit: pwd && pwd === confirmPwd

}))

)

.subscribe(({ match, canSubmit }) => {

errorLabel.innerText = match ? "" : "密码不一致";

if (canSubmit) {

submitBtn.removeAttribute("disabled");

} else {

submitBtn.setAttribute("disabled", true);

}

});

没看出代码和上面那张图有什么相似?我们来拆解一下。

const pwd$ = fromEvent(pwd, "input").pipe(map(e => e.target.value));

const confirmPwd$ = fromEvent(confirmPwd, "input").pipe(

map(e => e.target.value)

);

afd74122288a752b57eeacae8b9fd94f.png

我们把 pwd$, confirmPwd$ 称作流,可以把它们想象成河流,里面流淌着数据。

map 把流中的 input event 转换为输入框的 value。

combineLatest(pwd$, confirmPwd$);

aa9f37db3a2aadaeb9741b1ee5635ae2.png

combinLatest 的作用在这里有两个。

combine:把 pwd$, confirmPwd$ 合成一个新流

latest:新流中的数据为 pwd$, confirmPwd$ 最新的数据的组合

pwd$ 产生数据 a 时,confirmPwd$ 还没产生过数据,新流不产生数据;

pwd$ 产生数据 ab 时,confirmPwd$ 还没产生过数据,新流不产生数据;

confirmPwd$ 产生数据 a 时,

由于 pwd$, confirmPwd$ 都产生过数据了,pwd$ 流最新产生的数据为 ab,

新流产生数据 [ab, a];

confirmPwd$ 产生数据 ab 时,

由于 pwd$, confirmPwd$ 都产生过数据了,pwd$ 流最新产生的数据为 ab,

新流产生数据 [ab, ab]。combineLatest(pwd$, confirmPwd$).pipe(

debounceTime(200),

map(([pwd, confirmPwd]) => ({

match: pwd === confirmPwd,

canSubmit: pwd && pwd === confirmPwd

}))

);

141c001e558008acb51237c27635e707.png

debounceTime(200) 的作用和普通做法里的 debounce 功效一样。

上游流产生 [ab, a] 时,新流不立刻把数据传给下游,而是要延迟 200ms。

200ms 不到,上游流又传来数据 [ab, ab],新流丢弃之前的数据。

200ms 后,上游流没有传来新数据,新流将 [ab, ab] 传给下游。

map 将 [ab, ab] 转化为 { match: true, canSubmit: true }。

再比较一下,是不是很像呢?

efd10cff878b36174b26037fbd33e03a.png

141c001e558008acb51237c27635e707.png

总结

函数式响应式编程创造的初衷就是解决 listener callback 逻辑表达不直观,代码乱成一团麻 的问题。

至于它为什么叫函数式响应式编程,是因为它的实现借鉴了函数式、响应式编程思想。

例如:

declarative

关注做什么,而不是怎么做。隐藏了很多细节。

reactive

函数式响应式做法,input 输入有变化,button 状态就会跟着变。

相比较 input 输入变了、再调一遍函数、根据函数输出修改 button 状态,要自动化。

这句话说的有漏洞,常规做法也很自动化。先跳过吧,以后写一篇响应式编程的文章。

......

......

相关文章:

  • 纯html无限级目录树,利用Ajax实现无限级目录树(.NET)[转载]
  • 微型计算机自动化控制专业,你也能考国家电网之自动控制类专业!
  • 计算机与现代教育的英语作文,雅思写作大作文范文:电脑与现代教育
  • 五年级英语短文计算机,有关于计算机的英语短文章
  • h5怎么引入html,在html文件引入其它html文件的几种方法
  • html排行榜代码手机版,移动端前端代码优化丨排名VS体验
  • 计算机应用技术教程试题大一,大一计算机导论期末考试试题模拟试题及答案
  • 嵌入式计算机技术分类,嵌入式系统的分类及应用
  • 初中计算机课程图文混排教案,七年级信息技术教案:图文的混合编排
  • 天津城建大学计算机学院官网,天津城建大学计算机与信息工程学院研究生导师简介-杨振舰...
  • 计算机文化基础的改革,计算机学生论文,关于对计算机文化基础课程改革相关参考文献资料-免费论文范文...
  • 鲁迅美术学院考计算机几级,鲁迅美术学院英语四级考试科目安排2020年上半年...
  • 计算机实验圆述职报告,实验员个人述职报告(三)
  • k3 wise组件服务器安装,金蝶 K3 WISE 中间层组件安装报错!
  • outlook服务器与本地文件,Outlook设置本地存储的方法
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 【391天】每日项目总结系列128(2018.03.03)
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • Docker容器管理
  • HTML中设置input等文本框为不可操作
  • LeetCode29.两数相除 JavaScript
  • mysql常用命令汇总
  • Python socket服务器端、客户端传送信息
  • Python学习之路13-记分
  • Redis 懒删除(lazy free)简史
  • Shadow DOM 内部构造及如何构建独立组件
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • webpack入门学习手记(二)
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 我看到的前端
  • 一个项目push到多个远程Git仓库
  • 一些css基础学习笔记
  • 云大使推广中的常见热门问题
  • 再次简单明了总结flex布局,一看就懂...
  • - 转 Ext2.0 form使用实例
  • gunicorn工作原理
  • RDS-Mysql 物理备份恢复到本地数据库上
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ###项目技术发展史
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (3)选择元素——(17)练习(Exercises)
  • (ibm)Java 语言的 XPath API
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (算法)求1到1亿间的质数或素数
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .htaccess配置常用技巧
  • .NET 4.0中的泛型协变和反变
  • .NET CLR Hosting 简介
  • .NET Framework 服务实现监控可观测性最佳实践
  • .net Stream篇(六)