移動端列表查詢最佳實踐

不管是 pc 端仍是移動端,無可避免都會涉及到列表查詢有關的操做,但對於這兩種不一樣的設備,其列表查詢的最佳處理方式也是徹底不一樣。前端

對於 pc 端列表查詢來講,前端一般是給與服務端當前須要獲取的數據量(如 pageCount,limit 等參數)以及所須要獲取數據的位置(如 pageSize,offset 等參數)做爲查詢條件。而後服務端而後返回數據總數,以及當前數據,前端再結合這些數據顯示頁面總數等信息。這裏我稱爲相對位置取數。git

對於移動端而言,沒有pc 端那麼大的空間展現以及操做,因此基本上都會採用下拉取數這種方案。github

那麼咱們在處理移動端列表查詢時候使用這種相對位置取數會有什麼問題呢?數據庫

相對位置取數存在的問題

性能劣勢

經過相對位置取數會具備性能問題,由於一旦使用 offset 信息來獲取數據,隨着頁數的增長,響應速度也會變的愈來愈慢。由於在數據庫層面,咱們每次所獲取的數據都是「從頭開始第幾條」,每次咱們都須要從第一條開始計算,計算後捨棄前面的數據,只取最後多條數據返回前端。後端

固然了,對於相對位置取數來講,數據庫優化是必然的,這裏我就很少作贅述了。對於前端開發來講,優秀的的查詢條件設計能夠在必定方面解決此問題。api

數據顯示重複

事實上,對於一個實際運行的項目而言,數據更新纔是常態,若是數據更新的頻率很高或者你在當前頁停留的時間太久的話,會致使當前獲取的數據出現必定的誤差。服務器

例如:當你在獲取最開始的 20 條數據後,正準備獲取緊接着的後 20 條數據時,在這段時間內 ,發生了數據增長,此時移動端列表就可能會出現重複數據。雖然這個問題在 pc 端也存在,可是 pc 端只會展現當前頁的信息,這樣就避免了該問題所帶來的負面影響。網絡

結合列表 key 維持渲染正確

咱們在上面的問題中說明了,移動端下拉加載中使用相對位置查詢取數是有問題的。性能

那麼,若是當前不能迅速結合先後端進行修改 api 的狀況下,當服務端傳遞過來的數據與用戶想要得的數據不一致,咱們必須在前端進行處理,至少處理數據重複問題所帶來的負面影響。優化

由於當前分頁請求時無狀態的。在分頁取到數據以後前端能夠對取得的數據進行過濾,過濾掉當前頁面已經存在的 key(例如 id 等可以肯定的惟一鍵)。

經過這種處理方式,咱們至少能夠保證當前用戶看到的數據不會出現重複。同時當列表數據能夠編輯修改的時候,也不會出現由於 key 值相同而致使數據錯亂。

經過絕對位置獲取數據

若是不使用相對位置獲取數據,前端能夠利用當前列表中的最後一條數據做爲請求源參數。前端事先記錄最後一條數據的信息。例如當前的排序條件爲建立時間,那麼記錄最後一條數據的建立時間爲主查詢條件(若是列表對應的數據不屬於我的,可能建立時間不能惟一決定當前數據位置,同時還須要添加 ID 等信息做爲次要查詢條件)。

當咱們使用絕對位置獲取數據時候,雖然咱們沒法提供相似於從第 1 頁直接跳轉 100 頁的查詢請求,但對於下拉加載這種類型的請求,咱們沒必要擔憂性能以及數據重複顯示的問題。

對於相對位置取數來講,前端能夠根據返回數據的總數來判斷。但當使用絕對位置取數時,即便獲取數據總數,也沒法判斷當前查詢是否存在後續數據。

從服務器端實現的角度來講,當用戶想要獲得 20 條數據時候,服務端若是僅僅只向數據庫請求 20 條數據,是沒法得知是否有後續數據的。服務端能夠嘗試獲取當前請求的數據條數 + 1, 如向數據庫請求 21 條數據,若是成功得到 21 條數據,則說明至少存在着 1 條後續數據,這時候,咱們就能夠返回 20 條數據以及具備後續數據的信息。但若是咱們請求 21 條數據卻僅僅只能獲取 20 條數據(及如下),則說明沒有後續數據。

如能夠經過 「hasMore」 字段來表示是否可以繼續下拉加載的信息。

{
  data: [],
  hasMore: true
}

結合 HATEOAS 設計優化

事實上,前面咱們已經解決了移動端處理列表查詢的問題。可是咱們作的還不夠好,前端還須要結合排序條件來處理並提供請求參數,這個操做對於前端來講也是一種負擔。那麼咱們就聊一下 HATEOAS 。

HATEOAS (Hypermedia As The Engine Of Application State, 超媒體即應用狀態引發) 這個概念最先出如今 Roy Fielding 的論文中。REST 設計級別以下所示:

  • REST LEVEL 0: 使用 HTTP 做爲傳輸方式
  • REST LEVEL 1: 引入資源的概念(每個資源都有對應的標識符和表達)
  • REST LEVEL 2: 引入 HTTP 動詞(GET 獲取資源/POST 建立資源/PUT 更新或者建立字樣/DELETE 刪除資源 等)
  • REST LEVEL 3: 引入 HATEOAS (在資源的表達中包含了連接信息。客戶端能夠根據連接來發現能夠執行的動做)

HATEOAS 會在 API 返回的數據中添加下一步要執行的行爲,要獲取的數據等 URI 的連接信息。客戶端只要獲取這些信息以及行爲連接,就能夠根據這些信息進行接下來的操做。

對於當前的請求來講,服務端能夠直接返回下一頁的信息,如

{
    data: [],
    hasMore: true,
    nextPageParams: {}    
}

服務端如此傳遞數據,前端就不須要對其進行多餘的請求處理,若是當前沒有修改以前的查詢以及排序條件,則只須要直接返回 「nextPageParams」 做爲下一頁的查詢條件便可。

這樣作的好處不但符合 REST LEVEL 3,同時也減輕了前端的心智模型。前端無需配置下一頁請求參數。只須要在最開始查詢的時候提供查詢條件便可。

固然,若是前端已經實現了全部排序添加以及查詢條件由服務端提供,前端僅僅提供組件,那麼該方案更能體現優點。 前端是不須要知道當前業務究竟須要什麼查詢條件,天然也不須要根據查詢條件來組織下一頁的條件。同時,該方案的輸入和輸出都由後端提供,當涉及到業務替換( 查詢條件,排序條件修改)時候,前端無需任何修改即可以直接替換和使用。

其餘注意事項

一旦涉及到移動端請求,不可避免的會有網絡問題,當用戶在火車或者偏遠地區時候,一旦下拉就會涉及取數,可是當前數據沒有返回以前,用戶屢次下拉可能會有屢次取數請求,雖然前端能夠結合 key 使得渲染不出錯,可是仍是會在緩慢的網絡下請求屢次,無疑雪上加霜。這時候咱們須要增長條件變量 loading。

僞代碼以下所示:

// 查詢
function search(cond) {
  loading = true  
  api.then(res => {
      loading = false
  }).catch(err => {
      loading = false
  })
}

// 獲取下一頁數據
function queryNextPage() {
    if (!nextPageParams) return
    if (!loading) return
    search(nextPageParams)
}

鼓勵一下

若是你以爲這篇文章不錯,但願能夠給與我一些鼓勵,在個人 github 博客下幫忙 star 一下。

博客地址

相關文章
相關標籤/搜索