在不断变化的JavaScript领域,响应式编程技术正越来越流行。本文章系列希望提供一些当前技术发展形况的信息,分享多个技术以及同一主题的不同变化。从像Elm一样的新的语言到Angular 2采纳了RxJS,对于每一个开发人员,不管他们使用什么开发,总有一些是适合他们的。
本文是“响应式JavaScript”系列中的一节。你可以通过RSS订阅以收到通知。
虽然响应式编程技术并不是什么新东西,但是在JavaScript和Web社区它才刚开始为人所注意。已经出现了各种不同的库,为开发人员解决问题提供了多种方式。更涌现出了完全基于响应式技术的语言,如Elm,这提供了更加广泛的选择。
虽然已经取得了十足的进步,但是对于Web开发者来说,选取这项技术任然相对少见。
InfoQ采访了三位嘉宾以了解响应式技术现在处于什么状况以及未来将何去何从。这些嘉宾使用不用的方式使用过响应式技术。
InfoQ:请自我介绍并介绍一下响应式技术是怎么融入到你们一直所做的事情上的。
Tylor:我是Cycle.js项目的核心贡献者,这个框架设计于帮助编写功能和响应式的JavaScript代码。我也是Most.js和XStream的核心贡献者,这两个都是类似于Rx的响应式库,但是在提供响应式流上工程的目标不同。
Cycle.js是一个完全围绕响应式流设计的框架。流适用于一切,从事件、HTTP请求、状态到你的程序的方方面面。
Brian H:我经常使用Elm并且刚刚圆满组织了第一届Elm大会, elm-conf 。我也帮助组织St. Louis会议,管理Elm的年度状况调查,并且在brianthicks.com上写一些关于Elm的东西。你可能会说我相当喜欢这门语言。
Elm使用Elm架构(Elm Architecture,称为TEA)中的响应式模式。本质上讲,你将状态存储在一个地方,然后使用消息类型返回一个新的部分状态。这对我的一个主要关注点十分有用:为DevOps工具开发图形化用户界面。这种风格的编程方式十分适合接收后台的结构化日志。默认情况下数据模型是吻合的,我不需要到处努力同步各状态筒(silo)间的状态。
Brian C:我是Most.js的创造者,它是一个强调极致性能和精简API的响应式编程库。响应式和函数式响应编程已经完全改变了我设计软件的思考方式,并且我在做每一个应用时几乎都在尽量使用这种概念。
我在Nowait当前的工作主要关注基于Node的微服务架构。我们一直在探索在服务器端使用(函数式)响应式编程(FRP)。响应式技术在前端JS应用中已经获得了很多关注。尽管迄今为止在如何将它应用于服务器端上所做的工作还比较有限,但我想这会成为非常令人兴奋的事的。
Tylor:到2016年,响应式库已经相当成熟、健壮和灵活。如果你的大型应用程序有一些独特需求,像Rx一样的库能用无数种方式帮你管理应用程序数据流。如果你应用程序的大小很重要,那么像XStream之类的其他类库也可以提供类似的功能,但是占用的空间(footprint)却小很多。像Most.js这样的库对有函数式编程背景的程序员非常有用,因为它支持fantasy land(fantasy-land support),并且是众多流行的响应式流库中唯一拥有函数式API的。如果你的应用程序非常看中性能,Most.js也非常有用。
随着ECMAScript Observable的起草,上述所有的库都能进行基本互操作,这与该草案是松散耦合的。但是,我对ECMAScript Observable某些方面的走向相当悲观,比如令牌取消(cancellation tokens)。并且,我能预见我和其他许多人针对这些需求将继续使用第三方库。
Brian C:我把当前的总体状态描述为“未到火候”。这可能听起来奇怪,因为我们有像RxJs和Most.js这样成熟的实现,它们正在应用到生产环境的应用程序和其他一些框架中,如Cycle.js和Angular 2。我接下来会尝试解释。
过去的两年中发生了一些激动人心的事情:响应式编程技术已经在一些前沿的前端JS中走到了台前,并且已经成为技术和考量(mindshare)的主流。但是,当前这一代的实现仍然有一些我们需要解决的问题。例如,选择Hot Observable还是Cold Observable会显著增加开发人员的认知负担,引入像钻石形状(diamond shapes)这样的怪异问题,比如combine(f, stream1, stream1)。虽然这些问题很少遇到,仍将会令许多开发者措手不及。社区正着手开始研究其他一些实现技术,包括能取得正确性的严格FRP方法,例如信号函数(signal function)、信号向量(signal vector)、基于拉取式的方法(pull-based)和基于推送拉取式的方法(push-pull-based)。这些能帮助我们创建能消除那些小毛病的实现。我认为我们应该投入更多精力研究他们以及它们怎么融入响应式JS世界。
我认为我们才刚刚接触到服务器端响应式的皮毛。其他一些社区(例如Java,包括Spring Framework、Netflix、Apache等等所做的工作) 已经在服务器端响应式和数据流编程方面进步巨大。我认为响应式技术是基于节点(node-based)的服务器端app的一次巨大胜利,尤其当我们开始考虑把它们连接到响应式前端。这是从下至上的响应式。
Tylor:通常在许多事上我都坚持务实的态度,但我觉得响应式技术可以并应该用到每个地方。当你在编写应用程序的时候,可以编写零散的应用程序片段,它们是分成一块一块的,自己管理自己的行为。被动式编程与之相反,它提倡通过方法编程,如Foo.setBar(x),这种方式是在Foo的外部定义Foo和外部(译者注:这里指的x)的依赖的。当使用响应式编程的时候,Foo将会监听外部并自己决定什么时候更新bar。你能在 这里 找到一个关于它的精妙讨论,它对响应式重要的原因解释得更好。
Brian H:我认为图形化用户界面是最容易理解的响应式编程应用。用户界面需要具有对现实生活的示能性(affordance),否则它就没有任何意义。当用户点击某个东西的时候,你真的应该有所响应。但是同时,事件也从服务器过来。你也需要响应这些事件!事件流的统一使响应式编程对这些应用相当有吸引力。也就是说,每一个系统都有需要响应的刺激物。响应式技术通常总会派上用场的,即使手上的系统并不完全是用这种风格编写的。
Brian C:我认为开发人员应该优先选择响应式技术实现的功能至少有几个大类:异步数据流和随事件实时变化的值。两种情况下,能够管理和协调许多时时发生的事情是非常关键的,这正是响应式技术的强项。
一个用户界面程序需要响应用户的输入事件,并且同时处理发送数据和事件到服务器和从服务器接收数据和事件。用户输入可能促使需要发送和接收数据,这些数据也引起用户界面的改变,当用户决定下一步怎么做后,这反过来可能引起新的输入事件。响应式技术给了开发人员一套工具,甚至DSL。DSL能清晰地用极有表现力的代码为所有这些东西建模。
从服务器端的角度考虑同样的问题相当有趣。服务器可能接收到通过HTTP或者WebSocket传过来的数据请求或者数据更新请求,反过来需要访问数据库和其他服务。服务器可能通过消息队列和其他服务交换事件。同样的,事件流以及及时响应事件并维护当前状态的最新视图是核心,响应式技术让建模变得简单多了,更容易做对。
我认为值得注意的是,除了代码风格、库、DSL等等,“响应式”代表了一种思考问题和解决方案的方式。正因如此,它不是免费的。要做到“响应式编程”或者应用响应式技术需要转变思维以及设计软件系统的方式。这需要时间,并且每个人都不一样。对我来说,这些时间相当值得花。
Brian H:让我们再回到用户界面和Elm架构。你的更新函数改变了你的状态树,然后你的视图函数渲染它。每条消息都经过这个流程,所以你的更新可预测。响应式编程最大的好处是稳定和精确的模型。
纯粹的函数式编程能让你在这方面更深入!既然我们相信我们的函数针对同样的输入返回同样的输出,我们就能回放消息。这意味着我们能围绕此预测性创建工作流。Elm的创造者,Evan Czaplicki,在Elm大会上用一种新概念的调试器对此进行了演示。使用该工具,QA和开发人员能够通过共享一个消息列表协作修复一个问题。然后你可以使用一个类似的消息列表确保这个缺陷不会再出现。正是响应式编程让这成为了可能。
Brian C:考虑并对随着时间的推移而发生的变更建模是很困难的。编写正确管理它的代码也是困难的。测试这个代码也是困难的!
对我来说一个巨大的好处就是能够以更简单更精确的方式对随着时间的推移而发生的变更建模。随着我更加地深入到响应式编程,尤其是它和函数式编程一起,I/O被推到了应用程序的边缘,我发现编写好的测试变得简单多了。
响应式技术能测试纯粹计算(甚至是对随时间推移的变更建模的计算)的建模,而不一定把它们挂接到真实的I/O。例如,通过将代码挂接到一个伪造的响应式事件流上,由它模拟一个压缩时间段内的WebSocket数据(这样你的测试就能很快地运行),我们就能测试一段在真实应用程序下需要接收WebSocket传过来的数据并更新用户界面的代码了。
在我最近做的一个小型用户界面项目上,客户端有99%的单元测试覆盖率。并且那些单元测试都运行在Node上面,花了差不多一秒。唯一没有覆盖的代码是直接访问文档(document)和窗口(window)对象设立一些初始UI事件流的引导程序代码。
类似地,通过使用像模拟的事件流替代真实的WebSocket这样的方式,能在没有服务器的情况下增量式地进行UI开发。不难想象使用录像(record)和回放(playback)测试这种场景下的事件流。
Brian C:我谈及过我以上一些想法。我认为将出现更加严格的响应式实现来处理当前这一代实现已经暴露出来的棘手问题。我认为我们将很可能看到更专业的实现,可能其中一些更专注于UI应用程序,其他一些更专注于大量快速数据(big/fast data)的服务器端应用程序、微服务架构等等。我认为我们将继续看到UI是我们的关注点,但是我也希望在JS服务器端我们能看到响应式技术发生一些令人兴奋的事。
观察ECMAScript Observable的提议怎么融入这幅图景将非常有趣,考虑到它似乎以作为一个语言级通用响应式原语为目标的。很可能它将仅仅成为许多简单情况的好的解决方案,但是当情况需要的时候(性能、高速/大量I/O等等),开发人员还是会寻求更专业的第三方实现。
总的来说,所有这些都将会让响应式技术和响应式思维更加成为JS社区的主体。
Brian H:该模式将继续实现更好的用法,但只能通过恰当的教育。一个经验丰富的开发人员能在没有清晰的框架或语言支持情况下使用响应式技术。对他们来说这就够了!我们想要在我们系统中使用新的想法。但同时,我们也需要注意将这教授给新人。如果我们想响应式技术成为标准,我们就需要乐于接受他们的关切。我觉得,把东西变得让新手容易使用,通常会让所有人更容易使用它。新手的眼睛会暴露出经验丰富用户忽视的问题。友好的社区和良好的初次体验会比任何技术优势走得更远。
Tylor Steinberger 是自学成才的开发人员,是Most.js、XStream和Cycle.js的核心贡献者。
Brian Hicks 是Asteris的CTO,Asteris是一家位于圣路易斯的DevOps咨询公司。他组织了 美国Elm大会 (elm-conf US),在 brianthicks.com 上发表关于Elm的博客(和其他一些东西),并运营着 St. Louis Tech Slack 。他喜欢骑着自行车在圣路易斯到处跑,和他妻子外出游玩以及 在推特上发一些关于他家猫咪的事 。
Brian Cavalier 是Most.js的创造者,也是 NoWait 的一名架构师。
在不断变化的JavaScript领域,响应式编程技术正越来越流行。本文章系列希望提供一些当前技术发展形况的信息,分享多个技术以及同一主题的不同变化。从像Elm一样的新的语言到Angular 2采纳了RxJS,对于每一个开发人员,不管他们使用什么开发,总有一些是适合他们的。
本文是“响应式JavaScript”系列中的一节。你可以通过RSS订阅接收通知。
查看英文原文: https://www.infoq.com/articles/virtual-panel-reactive-javascript-and-elm-in-2016
感谢冬雨对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号: InfoQChina )关注我们。