前端資料正規化化

瀟湘待雨發表於2019-02-19

前言

現代web應用的飛速發展,特別是資料驅動思想指導下的React、vue等框架的出現,讓我們越來越需要關注資料的組織管理。隨著應用複雜度的提升,如果不對資料進行有效合理的設計拆分,那麼從效能、可維護性等方面來看會逐漸成為一種阻礙。所以我們需要關注前端資料設計。

其實沒有一種很明確的規範告訴我們具體到前端的資料結構應該如何去設計。關聯式資料庫設計有很多正規化,借鑑而不照搬結合前端自身特點,才是好的前端資料正規化化的實踐。

正規化化

在深入瞭解資料正規化化之前,我們可以先看個例子

舉個栗子:

實際業務中,迭代比較多的業務,我們一般會配置化,即除了業務資料之外將頁面佈局展示相關的內容也由介面控制。 那麼後端返回的資料可能如下:

{
    info: [
        {
            key:'a',
            txt:'展示1',
            value:0
        },
        {
            key:'b',
            txt:'展示2',
            value:1
        }
    ]
}
複製程式碼

這樣響應操作的時候,需要更新每一項的值如果直接修改info這個陣列,存在著很大的不便。
如果你說還好,但這樣將就操作之後,提交的時候發現這一大串冗餘資料後端也不需要呀,還是要處理value。
此時的資料還不是那麼的複雜,不過層層巢狀的物件見過吧,讓人心頭一驚的資料格式,如果還在上面操作,可能下個迭代你自己都不知道到底該操作哪個欄位了。

這時候如果將展示和邏輯相分離,抽出來一個專門的屬性用來存放與後端互動的資料,看起來是簡潔了一些,後期可維護性也增強了不少。

{
    info: [
        {
            key:'a',
            txt:'展示1'
        },
        {
            key:'b',
            txt:'展示2'
        }
    ],
    values:{
        a:0,
        b:1
    }
}
複製程式碼

這樣其實就可以認為是我們提到正規化化或者說是扁平化了。具體到前端資料正規化化之前 我們來看看資料庫的正規化吧

具體到前端資料正規化化之前 我們來看看資料庫的正規化吧

什麼是正規化:
顧名思義,一個規範模式(雖然有點粗暴,但好像就是這麼回事)。 本來想找段定義貼在下面,不過看了看太生硬了,寫下個人見解好了。

第一正規化 1NF 表的列具有原子性,不可再分解。 只要是關係型資料庫就滿足1NF

第二正規化 2NF 前提是滿足1NF,在1NF的基礎上。每一行或者例項必須唯一可以被區分,即需要我們說的主鍵(key)。

第三正規化 3NF 滿足1NF和2NF,且一個資料庫表中不包含已在其他表中包含的非主鍵欄位。
也就是說表中不冗餘,可以通過關係從其他表中獲取就不要單獨存放了,也就是相關資訊可以通過外來鍵相關聯。 有個圖表達的很不錯,借來一用:
前端資料正規化化

當然後面還有其他正規化這裡就先不提了。

總結一下,正規化就是為了減少冗餘,提高效率 遵循的正規化越高,冗餘越小,但也要具體分析,不可一味追求符合正規化。 有些時候一昧的追求正規化減少冗餘,反而會降低資料讀寫的效率,這個時候就要反正規化,利用空間來換時間。

redux中的state設計要求

redux針對state的設計也提出了正規化化的要求,對於複雜的資料結構,除了資料重複之外,還可能有下面這些問題:

  • 當資料在多處冗餘後,需要更新時,很難保證所有的資料都進行更新。
  • 巢狀的資料意味著 reducer 邏輯巢狀更多、複雜度更高。尤其是在打算更新深層巢狀資料時。
  • 不可變的資料在更新時需要狀態樹的祖先資料進行復制和更新,並且新的物件引用會導致與之 connect 的所有 UI 元件都重複 render。儘管要顯示的資料沒有發生任何改變,對深層巢狀的資料物件進行更新也會強制完全無關的 UI 元件重複 render

所以,在 Redux Store 中管理關係資料或巢狀資料的推薦做法是將這一部分視為資料庫,並且將資料按正規化化儲存。 有這麼幾點概念:

  • 任何型別的資料在 state 中都有自己的 “表”。
  • 任何 “資料表” 應將各個專案儲存在物件中,其中每個專案的 ID 作為 key,專案本身作為 value。
  • 任何對單個專案的引用都應該根據儲存專案的 ID 來完成。
  • ID 陣列應該用於排序。

具體實踐-Normalizr

這裡就需要提到Normalizr了,對於複雜資料管理,基本都會提到它。其作用很直白的通過其簡介體現出來:Normalizes nested JSON according to a schema。依據模式規範化的處理json。
其用法這裡就不介紹了,只提供下轉換前後的資料做個對比。有興趣的大家去官網一看便知。

原始資料:

{
  "id": "123",
  "author": {
    "id": "1",
    "name": "Paul"
  },
  "title": "My awesome blog post",
  "comments": [
    {
      "id": "324",
      "commenter": {
        "id": "2",
        "name": "Nicole"
      }
    }
  ]
}
複製程式碼

轉換後

{
  result: "123",
  entities: {
    "articles": {
      "123": {
        id: "123",
        author: "1",
        title: "My awesome blog post",
        comments: [ "324" ]
      }
    },
    "users": {
      "1": { "id": "1", "name": "Paul" },
      "2": { "id": "2", "name": "Nicole" }
    },
    "comments": {
      "324": { id: "324", "commenter": "2" }
    }
  }
}
複製程式碼

這樣的資料就比較符合我們前面redux設計要求了。

結束語

到這裡前端資料的正規化化也就介紹的差不多了,一個感悟是js中的資料結構設計何嘗不是資料庫設計,去遵循相應的正規化會讓我們的資料結構更加清晰明瞭。
就算開始沒考慮到,隨著業務量級的上升原本結構遇到的問題,開發的時候自然也會去往更優雅的方向去靠,這就是進步的過程。
不過還是那句話,要基於實際情況來看待,不要盲目引入,化簡為繁不是一種值得稱讚的做法。 通篇文章為個人見解,拋磚引玉有不對的地方歡迎指出

參考文章:

blog.csdn.net/qq_35401191…
zhuanlan.zhihu.com/p/36487766
cn.redux.js.org/docs/recipe…

相關文章