百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>html5教程> 前端相应式编程的方案及其缺陷的细致介绍(附代码)
分享文章到:

前端相应式编程的方案及其缺陷的细致介绍(附代码)

发布时间:09/01 来源:未知 浏览: 关键词:
本篇文章给大家带来的内容是关于前端响应式编程的方案及其缺陷的具体介绍(附代码),有必然的参照 价值,有需要的伴侣可以参照 一下,但愿对你有所帮忙。

实际世界有许多是以响应式的方式运作的,例如我们会在收到别人的发问,然后做出响应,给出响应的答复。在开发历程中我也利用了大量的响应式设计,积存了一些经历,但愿能举一反三。

响应式编程(Reactive Programming)和一般的编程思绪的主要不同在于,响应式以推(push)的方式运作,而非响应式的编程思绪以拉(pull)的方式运作。例如,事件就是一个很常见的响应式编程,我们平常会这么做:

button.on('click', () => {  
    // ...})

而非响应式方式下,就会变成这样:

while (true) {  
    if (button.clicked) {        // ...
    }
}

明显,不管在是代码的文雅度还是施行效力上,非响应式的方式都不如响应式的设计。

Event Emitter

Event Emitter是大多数人都很熟知的事件实现,它很简便也很有用,我们可以利用Event Emitter实现简便的响应式设计,例如下面这个异步搜索:

class Input extends Component {  
    state = {        value: ''
    }
    onChange = e => {        this.props.events.emit('onChange', e.target.value)
    }
    afterChange = value => {        this.setState({
            value
        })
    }
    componentDidMount() {        this.props.events.on('onChange', this.afterChange)
    }
    componentWillUnmount() {        this.props.events.off('onChange', this.afterChange)
    }
    render() {        
    const { value } = this.state        
    return (            <input value={value} onChange={this.onChange} />
        )
    }
}
class Search extends Component {  
    doSearch = (value) => {
        ajax(/* ... */).then(list => this.setState({
            list
        }))
    }
    componentDidMount() {
        this.props.events.on('onChange', this.doSearch)
    }
    componentWillUnmount() {
        this.props.events.off('onChange', this.doSearch)
    }
    render() {
        const { list } = this.state
        return (            <ul>
                {list.map(item => <li key={item.id}>{item.value}</li>)}            </ul>
        )
    }
}

这里我们会发明用Event Emitter的实现有许多缺陷,需要我们手动在componentWillUnmount里停止资源的开释。它的表达能力不足,例如我们在搜索的时候需要聚合多个数据源的时候:

class Search extends Component {  
    foo = ''
    bar = ''
    doSearch = () => {
        ajax({
            foo,
            bar
        }).then(list => this.setState({
            list
        }))
    }
    fooChange = value => {        this.foo = value        this.doSearch()
    }
    barChange = value => {        this.bar = value        this.doSearch()
    }
    componentDidMount() {        this.props.events.on('fooChange', this.fooChange)        this.props.events.on('barChange', this.barChange)
    }
    componentWillUnmount() {        this.props.events.off('fooChange', this.fooChange)        this.props.events.off('barChange', this.barChange)
    }
    render() {        // ...
    }
}

明显开发效力很低。

Redux

Redux采纳了一个事件流的方式实现响应式,在Redux中由于reducer必需是纯函数,因此要实现响应式的方式只要订阅中或者是在中心件中。

假如通过订阅store的方式,由于Redux不克不及准确拿到哪一个数据放生了转变,因此只能通过脏检查的方式。例如:

function createWatcher(mapState, callback) {  
    let previousValue = null
    return (store) => {
        store.subscribe(() => {            const value = mapState(store.getState())            if (value !== previousValue) {
                callback(value)
            }
            previousValue = value
        })
    }
}const watcher = createWatcher(state => {  
    // ...}, () => {    // ...})

watcher(store)

这个办法有两个缺陷,一是在数据很复杂且数据量比力大的时候会有效力上的问题;二是,假如mapState函数依靠上下文的话,就很难办了。在react-redux中,connect函数中mapStateToProps的第二个参数是props,可以通过上层组件传入props来获得需要的上下文,但是这样监听者就变成了React的组件,会随着组件的挂载和卸载被创立和烧毁,假如我们但愿这个响应式和组件无关的话就有问题了。

另一种方式就是在中心件中监听数据转变。得益于Redux的设计,我们通过监听特定的事件(Action)就可以得到对应的数据转变。

const search = () => (dispatch, getState) => {  
    // ...}const middleware = ({ dispatch }) => next => action => {  
    switch action.type {        case 'FOO_CHANGE':        case 'BAR_CHANGE': {            const nextState = next(action)            // 在本次dispatch完成今后再去停止新的dispatch
            setTimeout(() => dispatch(search()), 0)            return nextState
        }        default:            return next(action)
    }
}

这个办法能解决大多数的问题,但是在Redux中,中心件和reducer实际上隐式订阅了所有的事件(Action),这明显是有些不合理的,虽然在没有机能问题的前提下是完全可以接受的。

面向对象的响应式

ECMASCRIPT 5.1引入了getter和setter,我们可以通过getter和setter实现一种响应式。

class Model {  
    _foo = ''
    get foo() {        return this._foo
    }
    set foo(value) {        this._foo = value        this.search()
    }
    search() {        // ...
    }
}// 当然假如没有getter和setter的话也可以通过这种方式实现class Model {  
    foo = ''
    getFoo() {        return this.foo
    }
    setFoo(value) {        this.foo = value        this.search()
    }
    search() {        // ...
    }
}

Mobx和Vue就使用了这样的方式实现响应式。当然,假如不思考兼容性的话我们还可以使用Proxy。

当我们需要响应若干个值然后得到一个新值的话,在Mobx中我们可以这么做:

class Model {  
    @observable hour = '00'
    @observable minute = '00'
    @computed get time() {        return `${this.hour}:${this.minute}`
    }
}

Mobx会在运转时收集time依靠了哪些值,并在这些值发生改动(触发setter)的时候从新运算time的值,明显要比EventEmitter的做法利便高效得多,相对Redux的middleware更直不雅。

但是这里也有一个缺陷,基于getter的computed属性只能描写y = f(x)的情形,但是实际中许多状况f是一个异步函数,那么就会变成y = await f(x),关于这种情形getter就没法描写了。

关于这种情形,我们可以通过Mobx供给的autorun来实现:

class Model {  
    @observable keyword = ''
    @observable searchResult = []    constructor() {
        autorun(() => {            // ajax ...
        })
    }
}

由于运转时的依靠收集历程完全是隐式的,这里经常会碰到一个问题就是收集到不测的依靠:

class Model {  
    @observable loading = false
    @observable keyword = ''
    @observable searchResult = []    constructor() {
        autorun(() => {            if (this.loading) {                return
            }            // ajax ...
        })
    }
}

明显这里loading不该该被搜索的autorun收集到,为了处置这个问题就会多出一些额外的代码,而余外的代码容易带来犯错的时机。 或者,我们也可以手动指定需要的字段,但是这种方式就不得不多出一些额外的操纵:

class Model {  
    @observable loading = false
    @observable keyword = ''
    @observable searchResult = []
    disposers = []
    fetch = () => {        // ...
    }
    dispose() {        this.disposers.forEach(disposer => disposer())
    }    constructor() {        this.disposers.push(
            observe(this, 'loading', this.fetch),
            observe(this, 'keyword', this.fetch)
        )
    }
}class FooComponent extends Component {  
    this.mode = new Model()
    componentWillUnmount() {        this.state.model.dispose()
    }    // ...}

而当我们需要对时间轴做一些描写时,Mobx就有些力所不及了,例如需要延迟5秒再停止搜索。

相关引荐:

拼图响应式前端框架版响应式后台正式公布_html/css_WEB-ITnose

使用很简便的响应式前端开发框架_html/css_WEB-ITnose

以上就是前端响应式编程的方案及其缺陷的具体介绍(附代码)的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有150人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板