日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vuex 源码还有一些缺陷?

發布時間:2023/12/9 vue 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vuex 源码还有一些缺陷? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我看了vuex3和vuex4的源碼也輸出了文章,看到這篇時,vuex還有缺陷?看了看確實是好文,不愧是大佬寫的。文章不算長,推薦給大家看看。

點擊下方卡片關注我、加個星標
學習源碼整體架構系列、年度總結、JS基礎系列


眾所周知,Vuex 是 Flux 架構的一種實現。Flux 清晰確立了數據管理場景下各種職能單位,其主要準則有:

  • 中心化狀態管理

  • 狀態只能通過專門?突變?單元進行變更

  • 應用層通過發送信號(一般稱 action),觸發變更

  • Vuex 也是緊緊圍繞這些準則開發的,通過?store?類提供 Flux 模式的核心功能。在滿足架構的基本要求之外,則進一步設計了許多便利的措施:

  • 通過“模塊化”設計,隔離數據單元

  • 提供 getter 機制,提高代碼復用性

  • 使用?Vue.$watch?方法,實現數據流

  • 零配置,天然整合進 Vue 環境

  • 網上已經有很多解析的文章,沒必要贅述。本文僅就?中心化、信號機制、數據流?三個點的實現上展開,討論一下 Vuex 實現上的缺陷。

    中心化

    在Vuex中,store?整合了所有功能,是對外提供的主要接口,也是Flux模式下的數據管理中心。通過它,Vuex 主要對外提供了:

    • 信號相關的:?dispatch、commit

    • 偵聽器接口:?subscribe

    • state 值變更接口(替換state值,不應調用):?replaceState

    • state 模型變更接口(建議僅在按需引用場景下使用):registerModule、unregisterModule

    • 熱更新接口(HMR邏輯,不關注):hotUpdate

    官方實現的 store 非常復雜,耦合了許多邏輯。簡便起見,我們刨除各種旁路邏輯,只關注Flux架構的中心化、信號控制機制,可以總結出一份非常簡單的實現:

    export default class Store {constructor(options) {this._state = options.state;this._mutations = options.mutations;}get state() {return this._state;}commit(type, payload) {this._mutations[type].apply(this, [this.state].concat([...payload]));} }

    這是理解 Vuex 的核心,整份代碼只有兩個邏輯:

  • 通過_state屬性實現中心化、自包含數據中心層。

  • 通過?dispatch?方法,回調觸發事先注冊的_mutations方法。

  • 這份代碼有很多問題,舉例來說:

    • 使用簡單對象作為 state

    • 狀態的突變僅僅通過修改state對象屬性值實現

    • 沒有任何有效的機制,防止 state 對象被誤修改

    這些設計問題,在Vuex中同樣存在,這與Vue.$watch機制有非常密切的關系(見下文),個人認為這是極其不嚴謹的。

    信號機制

    Vuex 提供了兩個與信號有關的接口,其源碼可簡略為:

    export default class Store {...commit (_type, _payload, _options) {...const entry = this._mutations[type]this._withCommit(() => {entry.forEach(function commitIterator (handler) {handler(payload)})})this._subscribers.forEach(sub => sub(mutation, this.state))...}dispatch (_type, _payload) {...const entry = this._actions[type]return entry.length > 1? Promise.all(entry.map(handler => handler(payload))): entry[0](payload)}... }

    兩者之間的不同在于:

  • dispatch?觸發的是?action?回調;commit?觸發的?mutation?回調。

  • dispatch?返回 Promise;commit?無返回值。

  • 這樣的設計意圖,主要還是職責分離,action 單元用于描述?發生了什么;mutation用于修改數據層狀態state。Vuex 用相似的接口,將兩者放置在相同的地位上,這一層接口設計其實存在弊病:

  • action、mutation 各自需要一套type體系

  • 允許應用層繞過action,直接?commit?mutation

  • state 并非?immutable?的,而且在 action 中允許修改?state

  • 雖然確實提升了便利性,但對初學者而言,可能導致如下反模式:

    • 設計了兩套無法正交的type體系

    • 造成“直接提交mutation即可”的假象,破壞了Flux的信號機制

    • 在 action 中手誤修改了 state ,而沒有友好的跟蹤機制(這一點在getter中特別嚴重)

    由于沒有確切有效的機制防止錯誤,在使用Vuex的過程中,需要非常非常警惕;需要嚴謹正確地使用各種職能單元;或者以規范填補設計上的缺陷。

    單向數據流

    這里的數據流是指從 Vuex 的 state 到 Vue 組件的props/computed/data?等狀態單元的映射,即如何在組件中獲取state。Vuex 官方推薦使用 mapGetter、mapState 接口實現數據綁定。

    mapState

    該函數非常簡單,代碼邏輯可梳理為:

    export const mapState = normalizeNamespace((namespace, states) => {const res = {}...normalizeMap(states).forEach(({ key, val }) => {res[key] = function mappedState() {...return typeof val === 'function' ?val.call(this, state, getters) :state[val]}})...return res })

    mapState 直接讀取 state 對象的屬性。值得注意的一點是,res[key]一般作為函數掛載在外部對象,此時函數的this指向掛載的 Vue 組件。

    mapGetter

    該函數同樣非常簡單,其代碼邏輯為:

    export const mapGetters = normalizeNamespace((namespace, getters) => {const res = {}normalizeMap(getters).forEach(({ key, val }) => {res[key] = function mappedGetter() {...return this.$store.getters[val]}...})return res })

    mapGetter 訪問的則是組件掛載是?$store?實例的 getters 屬性。

    從 state 到 getter

    Vuex 的 getter屬性 與 Vue 的computed屬性在各方面的特性都非常相似,實際上,getter 正是基于 computed 實現的。其核心邏輯有:

    function resetStoreVM(store, state, hot) {...store.getters = {}const wrappedGetters = store._wrappedGettersconst computed = {}// 遍歷 getter 配置,生成 computed 屬性forEachValue(wrappedGetters, (fn, key) => {computed[key] = () => fn(store)Object.defineProperty(store.getters, key, {// 獲取 vue 實例屬性get: () => store._vm[key],enumerable: true // for local getters})})// 新建 Vue 實例,專門用于監聽屬性變更store._vm = new Vue({data: {?state: state},computed})... }

    從代碼可以看出,Vuex 將整個 state 對象托管到vue實例的data屬性中,以此換取Vue的整個?watch?機制。而getter屬性正是通過返回實例的 computed 屬性實現的,這種實現方式,不可謂不精妙。問題則是:

  • Vuex 與 Vue 深度耦合,致使不能遷移到其他環境下使用

  • Vue 的watch機制是基于屬性讀寫函數實現的,如果直接替換根節點,會導致各種子屬性回調失效,即不可能實現immutable特性

  • 后語

    Vuex 給我最大的感覺是:便利,同樣的功能有各種不同語義的邏輯單元處理,職責分離方面做的非常好,如果嚴格遵循規范的話,確實能非常好的組織代碼;接口也很簡明易懂,對開發者非常友好。從用戶數量、影響力等方面來看,無疑是一個非常偉大的框架。這里提出來的一些觀點當然也是見仁見智的,目的不外乎拋磚引玉而已。


    最近組建了一個湖南人的前端交流群,如果你是湖南人可以加我微信 ruochuan12 拉你進群。


    今日話題

    湖南長沙互聯網據說發展還可以,所以建一個湖南人的前端交流群,歡迎湖南人進群。歡迎分享、收藏、點贊、在看我的公眾號文章~

    一個愿景是幫助5年內前端人走向前列的公眾號

    可加我個人微信?ruochuan12,長期交流學習

    推薦閱讀

    我在阿里招前端,我該怎么幫你(可進模擬面試群)

    2年前端經驗,做的項目沒技術含量,怎么辦?

    點擊方卡片關注我、加個星標

    ·················?若川簡介?·················

    你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》多篇,在知乎、掘金收獲超百萬閱讀。

    從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。

    同時,活躍在知乎@若川,掘金@若川。致力于分享前端開發經驗,愿景:幫助5年內前端人走向前列。

    總結

    以上是生活随笔為你收集整理的Vuex 源码还有一些缺陷?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。