美文网首页JavaScript
[JavaScript] 你所不知道的响应式编程

[JavaScript] 你所不知道的响应式编程

作者: 何幻 | 来源:发表于2016-05-09 15:00 被阅读2247次

    这几年Facebook的React火了,它涉及到了很多出乎意料的JSX,思维奇特的Redux。
    其中,响应式编程(Reactive Programming)和数据流的思想在React背后起到了推动作用。

    什么?响应式编程?
    我会呀,不就是让网页响应不同尺寸的设备吗?原理是CSS3的媒体查询。《响应式Web设计》

    非也非也。。
    维基百科上对响应式编程是这样解释的,

    In computing, reactive programming is a programming paradigm oriented around data flows and the propagation of change.

    响应式编程是面向数据流和变化传播的一种编程范型。
    它与其他编程范型混合后,产生了,面向对象的响应式编程(OORP),函数响应式编程(FRP)等一些"新"概念。


    1. ReactiveX

    本文主要介绍ReactiveX,它是响应式编程的一种实现。简称Rx,是Reactive Extensions的缩写。
    最初,它是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源。
    现在它已经扩展到了很多种语言中,例如Java,JS,.NET,Scala,Clojure,Swift等等。

    说起响应式编程,其实我们遇到过。
    在Excel中,我们让B1=A1/5,那么一旦我们修改了A1单元格的值,B1就会随着改变。
    即,B1响应了A1的变化,这就是响应式。

    在Web应用中,这样的场景更多,UI上的每个事件,都会造成一系列改变。
    我们可以通过注册回调函数来解决这个问题,
    可是,异步编程控制起来是一个难题,例如callback hell,
    于是,ES6加入了Promise,ES7提案了Await/Async等解决方案。

    而Rx采用了另外的方式,它结合了观察者模式和迭代器模式,用了一种称为Observable的数据结构。
    Observable是一层抽象,封装了同步数据和异步数据,
    通过Observable之间进行变换,将最终结果反映到观察者那里。
    它已经作为ES7的提案。

    What's the difference between an array and events? — Erik Meijer

    Observable统一了列表和事件。


    2. 列表上的高阶函数

    JS支持高阶函数,指的是JS的函数可以接受其他函数作为参数,或者可以把另一个函数作为返回值。
    这给了JS很强的表达能力和灵活性。

    JS的Array类型,有很多好用的高阶函数,例如,map,filter,reduce...
    我们先看看它们的用法吧。

    [1,2,3].map((x)=>2*x);    //[2,4,6]
    [1,2,3].filter((x)=>x%2!=0);    //[1,3]
    [1,2,3].reduce((v,m)=>m+v,0);    //6
    

    Underscore.js实现了很多其他的高阶函数,例如,take,reduce,pluck等等,
    ES5规范也在一定程度上受到了它的影响。

    例如:

    _.take([1,2,3],2);    //[1,2]
    

    高阶函数,让我们避免了使用列表的索引。
    这也使得它们可以用于其他集合类型中。


    3. Observable

    Observable就是这样的一种新型集合类型。
    它包含一系列的从被观察对象推送给观察者的值。

    var button=document.getElementById('button1');
    var clicks=Rx.Observable.fromEvent(button,'click');
    
    clicks.take(1)
        .subscribe((e)=>console.log('clicked'));
    

    Rx把按钮未来的所有点击事件看成了一个无穷长的序列,即Observable,
    因为不涉及索引,高阶函数就可以处理这个序列了。
    以上代码,轻松实现了只触发一次的点击事件。

    其中take,表示取该序列的第一项构成一个新的序列,
    subscribe表示连接Observable与Observer。


    4. Operator

    Rx提供了非常多的处理Observable的函数,称为Operators

    例如:
    range(n,len)
    从n开始,len个数字
    Rx.Observable.range(2,2)~[2,3]

    concatMap(fn)
    把Observable中的每个item替换成多个,并保持顺序

    fromArray(arr)
    把数组转为Observable

    fromEvent(dom,name)
    把dom元素的事件流转为Observable

    pluck(name)
    用item的名为name的属性值组成新的Observable
    Rx.Observable.fromArray({value:0},{value:1},{v:2}).pluck('value')~[0,1,undefined]

    debounce(time)
    过滤掉那些间隔小于time ms的item

    merge(obs)
    合并两个Observable

    filter(predicator)
    取出满足限制条件的item

    of(item1,item2,...)
    将参数列表转换成Observable

    interval(time)
    创建一个Observable,它每隔time ms发送一个数字


    5. Observer

    Observable可以通过Operator来转换,但最终要由观察者来订阅。
    Observer由下面的方法来创建,

    var observer=Rx.Observer.create(onNext,onError,onCompleted);
    observable.subscribe(observer);
    

    其中,onError,onCompleted可以省略,
    onNext在每推送一项到序列中时触发,
    onError在某个环节中throw出一个值时触发,
    onCompleted在整个Observable序列结束时触发。

    这样observable的改变就能通知给observer了。


    6. 手动创建Observable

    前文提到的Observable可以由列表或DOM事件得到(fromArray/fromEvent),
    Observable类型的对象也可以直接创建。

    var observable=Rx.Observable.create((observer)=>{
        observer.onNext(1);
        observer.onNext(2);
        observer.onCompleted();
    });
    

    通过主动对observer的调用,observer.onNext可以用于各种同步和异步的场景中。

    因为大部分操作Rx都提供了Operator,所以,直接创建Observable多用于底层的一些实现中。
    例如,Rx.DOM对象中提供了请求JSONP并转换成Observable的功能。

    var data=Rx.DOM.jsonpRequest({
        url:DATA_URL
    });
    

    结语

    响应式编程内容很多,改变了我们的看待事件的方式,
    我们先搭建起数据流的管道,然后等待数据沿着管道被数据源推送给观察者。
    这种思想统一了同步和异步,是比Promise更强大的处理方案。

    熟悉LINQ的同学可能有所体会,Rx好像LINQ的Method Syntax,
    把事件源看成了数据库进行查询LINQ to "Events",
    用一系列Lambda表达式串联得到最终结果。

    学习响应式编程,对学习React有很大帮助,
    也只有在数据流方面处理得当,才能避免意外增加View层的复杂度,
    我想,这才是Flux,Redux出现的根本原因吧。


    参考:
    Reactive programming
    ReactiveX
    Functional Programming in Javascript
    Reactive Programming with RxJS
    Query Syntax and Method Syntax in LINQ
    es-observable

    扩展阅读:
    Cycle.js
    Functional reactive programming
    Your Mouse is a Database
    Facebook just taught us all how to build websites
    Functional Reactive React.js

    相关文章

      网友评论

        本文标题:[JavaScript] 你所不知道的响应式编程

        本文链接:https://www.haomeiwen.com/subject/jqderttx.html