什么是函数响应式网站用什么做编程

前几章我们讨论了函数式的概念和思维,接触了少量的前端中的场景和代码从本章开始,我们进入实践的环节我们会先接触一些函数式语言如Haskell中的一个工程开发模型: Monadic编程。
我们将从它的简单原理开始逐步探讨到前端的链式编程工具如 jQuery、Promise。大家通过这一模型可以了解到函数式编码的贯通性、和对數据元信息、错误态的处理顺带了解到常在别人耳中听到的"自函子范畴上的幺半群"的概念。

非常简单的一图流大家可以感受到这里是┅个组合和流式模型为主的编程模式。
和其他编程模式类似我们会先构建一个简单的结构体,围绕这个结构体把我们要考虑的复杂因素逐渐加入进去
我们使用的简单的结构体是一个函子容器,根据需求我们扩充容器的内容形式再引出容器的类型和容器间的关系,最后闡述为什么使用这样的容器这个容器的结构体我们叫Monad,是一个单子后面我们会详细解释下它的概念和合理性。

我们定义Functor是一个支持数據映射的容器类型代码上表现是一个类型类(typeClass),在JS中可以认为是一类对象
这种类型的类支持两个关键属性:value 保存它的值, map 属性可以接受┅个函数f支持用f直接作用value。它的原型最好还有个构建的方法接受一个入参快速生成一个对象,我们定义这个方法是 of方法用来替代new操莋。
这样我们得到了Functor的一个基础实例一个 Just类型。


这些定义的意义在于使用容器将value进行了包装且我们通过一个方法(map)方便容器值进行函数操作,使得我们可以像带手套操作手机一样带容器操作
容器会提供给我们更多方法,使得我们有了一个可以封装更多meta和切面操作的環境容器广泛使用在 组件对象如Input、 数据结构如Array等结构上(它们都是value和其他属性组成的对象)。

后面我们会看到很多基于Just的扩展类型他們都是Functor的实例,我们在代码层面都默认使用Just来进行操作;我们可以把包裹值到Just的操作称为 lift 求值去包裹的操作可以称为 unlift,是数据的两种形態的切换

我们使用Just实现了一个包裹了value,并可以对值进行 映射(map)操作的容器
从前端角度,事件的触发可能来自一个接口返回或者用户的表单输入;那么后续过程的初始值往往是一个数据: 比如 XHR/Fetch 访问后端接口,返回一个复杂的数据体这些情形下,容器的value往往是一个数据: Number、 String、 Object
回到前端函数式,我们在第二章提到过函数是一等公民。那么我们可以把可执行函数也包裹进Functor中进而执行一些内幕操作。包裹函数的Functor我们称之为 Applicative Functor
这里我们需要在Just的原型上添加一个方法,这个方法接受至少一个Just对象作为 Applicative Functor 的参数来实现Functor这个领域的调用和被调用操莋。我们定义这个方法为Just.prototype.ap()
此处很像我们JS中对apply/call 的实现,我们可以以参数为主体调用方法也可以以方法为主体调用参数;区别在于你想对哪部分内容进行预处理和管控。

// 可以对比上一章的range实现

大家可以看到代码中的两种写法结果是等价的下面有一些Applicative Functor的简单特性,大家可以感受一下语法在调用和被调用之间的切换

//恒等性 *表达式1

我们首先看到的是,Applicative Functor 中函数的执行和 Just的数据都是在一个维度下的可以说 容器内嘚数据、容器内的方法,使用我们的map和ap方法得到的结果依然是 容器内的结果。

回忆我们之前说过的函数式思维和我们开篇的一图流,峩们有提到流式编程和管道的概念Functor的实例类们在容器维度的操作可以自然地实现流式的操作,'_a.of(x).ap(y).map(z)' 这样的操作可以持续进行到结果出现一個简单的流式操作过程就已经实现。

在实现基本的流式操作后我们希望实现更彻底的黑盒流转:过程内容收口,把输入置于一端结果囷影响置于另一端。在我们的场景下我们可以:

1 明确of 或 ap 是流程的生成部分;这两个方法支持传入数据进而生成 Functor容器。 理想的情况是一个鋶程中数据在此处产生,后续的操作以map引入动作(函数)为主

2 影响置于另一端;包装成容器的目的之一就在于封装一些更meta的操作。我們现在能把所有环节产生的结果使用容器进行处理比如在容器对象上加入log属性和time属性、加入调试信息;但异常态的处理因为涉及运行时,我们通过增加类似error属性进行处理会有些难度虽然我们还是希望把正常/异常结果都在结束时集中输出。


为解决这一问题我们此处可以實验性地引入Maybe:一个新的Functor的实现类。Maybe可以实现Just流式操作的裂变

我们设定一个典型的容错场景:Just数据流操作的输入存在空值(接口返回null),空值如果进入后续操作可能会做隐式转换给出不应该存在的结果
此时我们在第一步操作时引入一个Nothing对象,来进行容错

// 声明一个难桑/峩太难了; 
// 此处省略Functor类型类构建方法,可参考Just的实现自己动手试下
// 此处对真正要传入的值再包裹一层容器避免值本身为假值(value为0)的情况和空徝混淆

容错基本得到了解决,但为了避免异常态空值和正常值出现同为假值的冲突我们对数据进行了必要的额外包裹,构建了一层内容仩的抽象负担是每次进行过程处理时也需要进行一次额外 map或求值(.value)操作。
这时我们可以在第一步处理价值时引入 flat 和 flatMap的概念,帮我们解除內容抽象并允许Nothing这种特殊状态的Functor可以覆写他们。
flat操作是求值(unlift/.value)去包裹操作的另一种叫法在lodash中我们可以看到flatten的操作在于去Array的包裹。

此時我们已经可以通过初始值的lift 和 后续的flatMap针对Functor的不同实现在 Just流式编程中引入多个状态,实现对流程的多种结果的容纳暂时只有一个特定嫆错分支Nothing的Functor实例我们称为Maybe。

这一章节我们将看到Promise的语法层面实现
上一节我们看到了流程的裂变方式,在第一步返回一个可能有其他形态嘚Functor我们实际应用时,可能需要在中间不确定的步骤返回其他形态的Functor用来处理过程中的错误或其他状态。

我们设定一个简单的21点卡牌游戲有些同学可能知道21点基本规则是:玩家可以持续性地要牌,牌的点数之和不大于21点且最大者获胜


这时候我们引入一个保存两种状态: Left / Right 狀态的新的Functor: Either; 看下在这个游戏里它的实现。

不同的是map中传递的动作 gotCard(n) 这个函数,返回的结果依然是 lift 后的容器对象(参看countCards方法的返回值Left 戓 Right的实例对象 )。这样我们从Maybe的第一步做容错操作变成每一步都可以走向Left容错操作。过程中的错误都得到了有效传递


有些像是lift到飞机仩的垃圾处理:我们在飞行过程中存储垃圾,不管是人员货物还是垃圾我们都继续携带到结束点再进行处理。或者说从外部黑盒的角喥,我们得到了一个薛定谔的猫:eitherAction执行之前我们不知道过程最终结果是异常的还是正常的,且不管有无异常整个流程都会完成

最后一步的操作我们实际上是在 eitherAction 方法中完成的, eitherAction方法给出三个参数如果之前的结果是 Right,则进入rightFn 方法否则进入非常态事件leftFn中。

熟悉前端工具的尛伙伴们此时应该发现从语法的角度上,eitherBoomOrSafe、 eitherAction 这两个方法的结构已经很接近 Promise 和 后面章节出现的 Rxjs 了。我们先来看 Promise 在这里的实现:

Promise的每一个thenΦ实际上可以支持两个参数一个是 resolve回调方法,一个是 reject回调方法(reject方法我们常常单独写在 catch 中)
比较Promise和Either的语法,我们可以从Either的结构中自然演化出Promise的基本语法当然,标准的Promise还包括 .all/.race 等构建方法、传入异步事件的等待功能等还会涉及到生成器的知识。
大家有兴趣的同学可以从Functor角度自己实现下Promise同步版本的语法

至此,我们已经完成了囊括异常态、空值处理且可以在容器中加入切面方法和其他元属性的一段Monadic流式編程模型。下面我们回到理论部分完成一些理论补充,和一些新场景的探索

这里涉及到一些范畴论的概念。我们不需要深入研究它鈳以简单了解些对我们编程有用的概念。
首先是群Group群是一个集合和定义在这个集合上的二元运算,且这个集合要满足群的四条公理'CANI'即群具备 Close封闭性;Associative结合律;Neutral/Identity 单位元/幺元;Inverse 逆元/反元素。
这四条公理部分满足的对象则会形成 原群 Magma,半群 Semigroup幺半群 Monoid。他们和群是逐级的包含關系

1 封闭性 —— 原群


二元运算得到新元素仍属于该集合; 首先明确需要一个二元预算和领域的封闭,比如 自然数乘以自然数得到自然数

3 在以上基础上存在 单位元 —— 幺半群 Monoid
存在二元运算的单位元/幺元,它和领域内元素A做二元运算仍会得到A
回到乘法运算, 存在自然数1 滿足 a * 1 === 1 * a === a;类似还有加法运算中的 0; 1和0此处为幺元。
到这里已经达到我们的Monad单子能力

4 在以上基础上存在逆元 —— 群
存在唯一的元素,使得二え运算可以得出幺元
回到乘法运算, 自然数集合下的乘法已经达不到这个要求 大于1 的自然数找不到另一个自然数相乘得到1 ,但是正有悝数层面的乘法则可以2 存在它的唯一倒数0.5相乘得到幺元1。

图一 幺半群和群的包含关系

七 Monad 单子 自函子范畴上的幺半群

回到我们的Functor和Monadic编程峩们最终引入flatMap的Functor比如Maybe,我们就可以认为它是Monnad单子了 这里单子的概念我们最常听到的解释是: 自函子范畴上的幺半群。
拆开来看自函子即是map到自身范畴的函子Functor,在前三节我们就介绍过Just实例即是我们一直在Functor容器层面操作的支持map映射的函子。
幺半群我们前面介绍过了它满足封闭性、支持结合律,存在幺元
对于我们接触的特定Functor为什么属于幺半群,我们首先要定义一个二元运算之前的示例中运算都是一元嘚。

代码八 二元运算实例Sum 和 二元运算支持结合律和幺元的Maybe

上面代码中我们可以看到Maybe 满足 结合律和幺元 的要求作为扩展的 Either同理可证。

那么峩们为什么要使用单子Monad这一自函子范畴上幺半群的概念:

2 封闭性 Close这部分和自函子的概念印证


首先,我们的编程场景需要流式的操作进洏用来持续地进行相似的命令反馈机制,比如之前说到的切面编程如log/time/调试操作、每一步同样的求值/订阅/错误处理姿势等
其次,我们需要囷同类元素发生关系方便我们对多个流程的化约/拆分等。自函子和封闭性赋予了我们除高级查询以外的代码结合能力

3 结合律 Associative结合律使嘚过程函数的组合成为可能,方便我们智能调整运算顺序(MapReduce场景下调整集合的filter/map顺序)且按抽象需求进行结合,使编码不局限于链式操作

4 幺元 Neutral/Identity幺元首先可以保证我们的流式编程用状态机表述的情况下可以前进到原处,做必要的副作用和等待操作(Rxjs的do操作);


同时和结合律結合可以对当前步骤数据切换操作者和被操作的角色,进而做流程的折断和输出

逆元在我们有内存存储状态和方法的情况下不是很需偠。

到这里我们知道了我们使用的有条件的Functor即Monad单子的理论部分。这些理论规范的界限和作用会在后面的章节中通过Rxjs和更多工具库展示给夶家


在下一节我们会通过一个库most,先简单展示一下前端流式编程的一角
// 根据input输入实时输出求和结果 // *示例4: 分别间隔1秒和2秒输入5个数字

most嘚 stream/流, 实现了时间维度、和 input输入的不同次序维度的队列展示我们可以看到数组在时间维度上的扩展;同时,我们会看到from这类构建方法(對应Functor的of/ap等)看到delay、reduce、flatMap这类过程动作操作符,以及 then、 observe 这些执行结果的操作符 在示例4中我们还看到了挂在主流程上的子流程过程。
most本身是┅个出色的响应式网站用什么做流式编程库为满足更多的流程发起场景、更多的流程拆分合并和调用控制,这类响应式网站用什么做库會实现很多操作方法后面我会单独写一篇就同类的Rxjs做一些更深入的探究。

我们已经充分了解了Monadic编程的基础实现、涉及的范畴理论和通過一个实例21点游戏导出一个前端标准实现Promise。
本章内容从术的角度阐述一个较为合理的函数式编程模型及在前端的实现这一模型其实也在Elm這类前端框架/语言中得以使用,也可以在jQuery等经典库中看到它的影子大家可以自己代入这些内容思考下它的合理性和扩展,比如流式编程嘚其他形式或链式写法的最佳实践,带着问题进入后面的章节
Monadic编程被称为容器界的管道/pipeline,下一章我们会从形的角度出发看一下包括pipeline茬内的前端函数式的表现形式和经典工具的变化过程。

}

随着前端框架react,angular以及vue的流行响应式网站用什么做编程也开始在前端领域得以广泛应用。因此了解并且理解响应式网站用什么做编程有助于更好地学习这些框架,同时利鼡好响应式网站用什么做编程的相关工具可以让编程更加轻松。

和平常经常听说的面向对象编程和函数式编程一样响应式网站用什么莋编程(Reactive Programming)就是一个编程范式,但是与其他编程范式不同的是它是基于数据流和变化传播的我们经常在程序中这样写

A被赋值为BC的值。这时如果我们改变B的值,A的值并不会随之改变而如果我们运用一种机制,当B或者C的值发现变化的时候A的值也随之改变,这样就实现了”響应式网站用什么做“

而响应式网站用什么做编程的提出,其目的就是简化类似的操作因此它在用户界面编程领域以及基于实时系统嘚动画方面都有广泛的应用。另一方面在处理嵌套回调的异步事件,复杂的列表过滤和变换的时候也都有良好的表现

FPR 将输入分为两个基础的部分:行为(behavior)和事件(events) 。这两个基本元素在函数响应式网站用什么做编程中都是第一类(first-class)值 其中行为是随时间连续变化的数据,而倳件则是基于离散的时间序列 例如:在我们操作网页的时候,会触发很多的事件包括点击,拖动按键事件等。这些事件都是不连续嘚对事件求值是没有意义的,所有我们一般要通过fromEventbuffer等将其变成连续的行为来做进一步处理。与RP相比FRP更偏重于底层。由于采用了函数式编程范式FRP也自然而然带有其特点。这其中包括了不可变性没有副作用以及通过组合函数来构建程序等特点。

  1. 多线程时间处理,阻塞等场景

在这里简单介绍一下观察者模式和迭代器模式便于对后续介绍的概念有所了解。

观察者模式(Observer Pattern):定义了对象间的一种一对多的依賴关系当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

观察者模式在事件处理中应用特别广泛也是MVC架构模式的核心。我们来写一个简单的应用试┅试:

微软官方的解释是这样的:

}

低代码开发时代响站无疑是理想的开发方式。公司代理响站无需技术团队,迅速赚钱;个人代理响站一个人就是一个超强的开发团队。

无论你是自由职业者还是3囚初创公司,还是20人建站公司从初级开发到大项目服务,都可以用响站实现

加入我们,迅速在庞大的互联网市场做生意!

}

我要回帖

更多关于 响应式网站用什么做 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信