<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        前端響應式編程的方案及其缺點的詳細介紹(附代碼)

        來源:懂視網 責編:小采 時間:2020-11-27 15:24:28
        文檔

        前端響應式編程的方案及其缺點的詳細介紹(附代碼)

        前端響應式編程的方案及其缺點的詳細介紹(附代碼):本篇文章給大家帶來的內容是關于前端響應式編程的方案及其缺點的詳細介紹(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。現實世界有很多是以響應式的方式運作的,例如我們會在收到他人的提問,然后做出響應,給出相應的回答。在
        推薦度:
        導讀前端響應式編程的方案及其缺點的詳細介紹(附代碼):本篇文章給大家帶來的內容是關于前端響應式編程的方案及其缺點的詳細介紹(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。現實世界有很多是以響應式的方式運作的,例如我們會在收到他人的提問,然后做出響應,給出相應的回答。在

        本篇文章給大家帶來的內容是關于前端響應式編程的方案及其缺點的詳細介紹(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

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

        響應式編程(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秒再進行搜索。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        前端響應式編程的方案及其缺點的詳細介紹(附代碼)

        前端響應式編程的方案及其缺點的詳細介紹(附代碼):本篇文章給大家帶來的內容是關于前端響應式編程的方案及其缺點的詳細介紹(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。現實世界有很多是以響應式的方式運作的,例如我們會在收到他人的提問,然后做出響應,給出相應的回答。在
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲一区影音先锋色资源| 精品少妇人妻AV免费久久洗澡 | 亚洲综合一区二区三区四区五区| 日本视频免费高清一本18| 亚洲人成77777在线播放网站| 人妻免费久久久久久久了| 亚洲不卡AV影片在线播放| 美女被艹免费视频| 亚洲av高清在线观看一区二区| 色婷婷六月亚洲综合香蕉| 免费看a级黄色片| 成人精品国产亚洲欧洲| 一级毛片直播亚洲| 一级做a爰黑人又硬又粗免费看51社区国产精品视 | 久久精品国产精品亚洲艾| a毛片全部播放免费视频完整18| 中文字幕在线亚洲精品| 国产一级婬片A视频免费观看| 久久精品国产精品亚洲精品| 99爱在线观看免费完整版| 中文字幕在线观看亚洲| 无码精品A∨在线观看免费| 亚洲人成网男女大片在线播放| 野花高清在线观看免费完整版中文 | sihu国产精品永久免费| 亚洲国产精品无码久久久蜜芽| 免费国产黄网站在线观看 | 亚洲狠狠色丁香婷婷综合| 国产一级高清视频免费看| 一级免费黄色毛片| 亚洲人成网www| 爽爽日本在线视频免费| 丝瓜app免费下载网址进入ios| 亚洲AV第一页国产精品| 久久久久国色AV免费观看性色| 激情吃奶吻胸免费视频xxxx| 国产亚洲精久久久久久无码| 在线观看无码AV网站永久免费| 免费一级毛suv好看的国产网站| 亚洲天堂男人天堂| 日韩在线天堂免费观看|