欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

前端響應式編程方案及其缺點是什么

小編給大家分享一下前端響應式編程方案及其缺點是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!

我們提供的服務有:成都網(wǎng)站制作、成都網(wǎng)站設計、外貿(mào)營銷網(wǎng)站建設、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、重慶ssl等。為上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的重慶網(wǎng)站制作公司

現(xiàn)實世界有很多是以響應式的方式運作的,例如我們會在收到他人的提問,然后做出響應,給出相應的回答。在開發(fā)過程中我也應用了大量的響應式設計,積累了一些經(jīng)驗,希望能拋磚引玉。

響應式編程(Reactive Programming)和普通的編程思路的主要區(qū)別在于,響應式以推(push)的方式運作,而非響應式的編程思路以拉(pull)的方式運作。例如,事件就是一個很常見的響應式編程,我們通常會這么做:

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

而非響應式方式下,就會變成這樣:

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

顯然,無論在是代碼的優(yōu)雅度還是執(zhí)行效率上,非響應式的方式都不如響應式的設計。

Event Emitter

Event Emitter是大多數(shù)人都很熟悉的事件實現(xiàn),它很簡單也很實用,我們可以利用Event Emitter實現(xiàn)簡單的響應式設計,例如下面這個異步搜索:

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>
        )
    }
}

這里我們會發(fā)現(xiàn)用Event Emitter的實現(xiàn)有很多缺點,需要我們手動在componentWillUnmount里進行資源的釋放。它的表達能力不足,例如我們在搜索的時候需要聚合多個數(shù)據(jù)源的時候:

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() {        // ...
    }
}

顯然開發(fā)效率很低。

Redux

Redux采用了一個事件流的方式實現(xiàn)響應式,在Redux中由于reducer必須是純函數(shù),因此要實現(xiàn)響應式的方式只有訂閱中或者是在中間件中。

如果通過訂閱store的方式,由于Redux不能準確拿到哪一個數(shù)據(jù)放生了變化,因此只能通過臟檢查的方式。例如:

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)  

這個方法有兩個缺點,一是在數(shù)據(jù)很復雜且數(shù)據(jù)量比較大的時候會有效率上的問題;二是,如果mapState函數(shù)依賴上下文的話,就很難辦了。在react-redux中,connect函數(shù)中mapStateToProps的第二個參數(shù)是props,可以通過上層組件傳入props來獲得需要的上下文,但是這樣監(jiān)聽者就變成了React的組件,會隨著組件的掛載和卸載被創(chuàng)建和銷毀,如果我們希望這個響應式和組件無關的話就有問題了。

另一種方式就是在中間件中監(jiān)聽數(shù)據(jù)變化。得益于Redux的設計,我們通過監(jiān)聽特定的事件(Action)就可以得到對應的數(shù)據(jù)變化。

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)
    }
}

這個方法能解決大多數(shù)的問題,但是在Redux中,中間件和reducer實際上隱式訂閱了所有的事件(Action),這顯然是有些不合理的,雖然在沒有性能問題的前提下是完全可以接受的。

面向對象的響應式

ECMASCRIPT 5.1引入了getter和setter,我們可以通過getter和setter實現(xiàn)一種響應式。

class Model {  
    _foo = ''
    get foo() {        return this._foo
    }
    set foo(value) {        this._foo = value        this.search()
    }
    search() {        // ...
    }
}// 當然如果沒有getter和setter的話也可以通過這種方式實現(xiàn)class Model {  
    foo = ''
    getFoo() {        return this.foo
    }
    setFoo(value) {        this.foo = value        this.search()
    }
    search() {        // ...
    }
}

Mobx和Vue就使用了這樣的方式實現(xiàn)響應式。當然,如果不考慮兼容性的話我們還可以使用Proxy。

當我們需要響應若干個值然后得到一個新值的話,在Mobx中我們可以這么做:

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

Mobx會在運行時收集time依賴了哪些值,并在這些值發(fā)生改變(觸發(fā)setter)的時候重新計算time的值,顯然要比EventEmitter的做法方便高效得多,相對Redux的middleware更直觀。

但是這里也有一個缺點,基于getter的computed屬性只能描述y = f(x)的情形,但是現(xiàn)實中很多情況f是一個異步函數(shù),那么就會變成y = await f(x),對于這種情形getter就無法描述了。

對于這種情形,我們可以通過Mobx提供的autorun來實現(xiàn):

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

由于運行時的依賴收集過程完全是隱式的,這里經(jīng)常會遇到一個問題就是收集到意外的依賴:

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秒再進行搜索。

看完了這篇文章,相信你對前端響應式編程方案及其缺點是什么有了一定的了解,想了解更多相關知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

新聞名稱:前端響應式編程方案及其缺點是什么
轉載來于:http://www.chinadenli.net/article48/pgdiep.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站虛擬主機建站公司響應式網(wǎng)站定制網(wǎng)站移動網(wǎng)站建設

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化