解析 Twitter 前端架構 學習複雜場景數據設計

前幾天刷Twitter,發現Nicolas(Engineering at @twitter. Technical Lead for Twitter Lite)發佈了這麼一條推文:javascript

twitter.jpeg

大致意思就是Twitter前端通過重構,已經徹底遷移到React+Redux+PWA技術棧了,後端也使用了nodeJS,實現了「前端一統天下」,lol。html

聽到這個消息以後,我以爲去深挖一下Twitter的Redux store組織架構,將會很是有意思。
這對於在複雜場景下的前端數據學習,以及React、Redux數據流設計十分有意義。前端

由於,在Redux數據流框架的思想下,對於數據的處理和分配徹底由前端掌握。
前端數據如何設計,設計的功力如何直接徹底決定整個項目的開發進度以及代碼強健性,甚至還決定着頁面的性能。java

本文將剖析Twitter前端數據結構層次,若是你對React技術棧不是很瞭解,也不妨礙閱讀;一樣,若是你對這套技術棧有興趣的話,歡迎參看個人其餘相似文章:node

歡迎關注個人主頁,更多技術文章再也不錯過。react

本文主體內容翻譯自Ryan Johnson的文章:Dissecting Twitter’s Redux Store,筆者進行了必定程度的拓展。git

準備工做

想要看Redux store的前提是你須要配有React Developer Tools (RDT),在RDT tab中選中應用根節點。
確保選中以後,在console面板中輸入:github

// $r is a shortcut that references the selected element in RDT
$r.store.getState();複製代碼

接下來,咱們就能夠看到Redux數據樹,就像圖中所示:redux

數據結構

設計分析

我建議你們花些時間對每一個不一樣的state進行展開,並加以學習。但在這篇文章中,因爲篇幅所限,我會挑選並深挖:後端

  • entities/tweets和
  • homeTimeline

兩個最主要也是最核心的state進行剖析。這兩個states包含了一條tweet的全部關聯數據。

一條tweet,就像下圖中我所發的:

推文舉例

一條tweet內容的數據信息所有存儲在entities/tweets/entities中,entities/tweets/entities能夠理解爲一個normalized的data table,它存儲了全部tweets推文的信息;
在這個table中,每一條tweet都是一個鍵值對類型的js object:key爲該條tweet的id,value爲該條tweet的數據,也是一個js object。

下圖中,我將第一條tweet展開,方便你們一探究竟:

推文設計.png

瞭解了tweet存儲結構,咱們接下來看一下Twitter首頁的timeline結構。
直觀上,timeline必定包含了我的主頁展現推文的信息。經過tweet id和剛纔介紹過的entities/tweets/entities中的tweet相匹配,並最終加以在timeline上展現。
以下圖:

timeline數據結構

每一個用戶的首頁timeline信息可homeTimelines/timeline找到。首頁timeline展現的順序,則按照timeline這個數組的順序。也就是說,timeline數組index爲0的條目,就是你在首頁timeline上看到的第一條tweet;

重要的話再說一遍:
首頁timeline上的每條tweet,都有一個惟一的id,這個id和上面介紹的,存儲在entities/tweets/entities之中的tweet id相匹配。

看到這裏,你也許會感嘆:

「This is pretty much normalizing state shape 101 from Dan Abramov!」

沒錯,這樣的範式也是Redux所推崇的,徹底的扁平化設計帶來的開發體驗和性能提高是無與倫比的。

固然,你可能會問爲何Redux設計哲學,包括Twitter都在推崇扁平化的數據結構呢?
這個問題建議參考:Redux core concepts,這裏講的很是清晰,被收錄在Redux core concepts中,強烈建議閱讀。
若是您英語吃力,能夠留言與我交流,就再也不展開了。

繼續言歸正傳,咱們來討論一下滾動時的異步請求設計。
首頁timeline加載新tweets方式有兩種:

  • 上拉加載 track tweets by top
  • 下滑加載 track tweets by bottom

第一種用於拉取更新的tweets,第二種用於拉取更舊的tweets;好比你新發了一條tweet,就要上拉,方可顯示在timeline上;若是沒有最新的,向下滑動到底部後,自動加載時間上更早的tweets。
用一個等式來表達:

top = new tweets,
and
bottom = older tweets

這種狀況下,homeTimelines下的lastFetch.bottom和lastFetch.top,分別爲時間戳,記錄最後一次更新數據的信息(上拉和下滑)。

  • lastFetch.bottom: 記錄最後一次向下滑動而更新數據的信息;
  • lastFetch.top: 記錄最後一次下上拉取而更新數據的信息;

同時,
cursor.bottom和cursor.top值分別爲一個tweet id,表示當前timeline上,最上邊和最底部分別是哪一條tweet。

  • cursor.bottom: 記錄屏幕最底部tweet ID;
  • cursor.top: 記錄屏幕最頂部tweet ID;

同時, homeTimelines裏面還記錄了isLoadingDirections.bottom和isLoadingDirections.top來表示數據加載的觸發源頭。

如圖:

記錄信息.png

最後一個很是有意思的是,entities下除了存在entities/tweets以外,還分別有cards, lists and users;

  • entities/tweets
  • entities/cards
  • entities/lists
  • entities/users

來表示不一樣的推文特性。

當你打開這其他三項的時候,會發現這三項與entities/tweets保持在相同的結構,他們都有一個fetchStatus的data table,key爲tweet id, value爲加載狀態,據統計一共有一下幾種:

  • ‘none’;
  • ‘loading’;
  • ‘loaded’;
  • ‘failed’.

狀態截圖

這幾種狀態的設置無外乎這麼幾個目的:

  • 保證在loading狀態或loaded的tweet不會再發送請求給server;
  • 在未加載完時,能夠顯示加載動畫或者展位圖;
  • 在加載失敗時,能夠顯示失敗提示或者在此請求時進行補救。

總結

本文分析了Twitter在採用Redux架構下的數據設計結構,在一個複雜的場景下,但願引發讀者對redux能有一個更深刻的認識。

本文主體內容翻譯自Ryan Johnson的文章:Dissecting Twitter’s Redux Store,筆者進行了必定程度的拓展。

Happy coding!

PS: 做者Github倉庫,歡迎經過代碼各類形式交流。

相關文章
相關標籤/搜索