無限捲軸的複雜度

重點摘要:重複使用 DOM 元素,並移除距離 檢視區域使用預留位置來處理延遲資料。歡迎參閱這篇 demoCode 捲動器。

在網際網路上,無限捲頁器會彈出。Google Music 的藝人名單是 第一,Facebook 的時間軸是一則 Twitter 的即時動態消息也包含在內個人中心 只要向下捲動,就能看到新內容 似乎出乎意料為使用者提供流暢的使用體驗,而且易於使用 看看申訴內容。

不過,無限捲動器背後的技術挑戰並不容易 似乎。《The Right ThingTM》的應用範圍 非常龐大一開始就考量頁尾連結, 因為內容不斷推進頁尾,這點相當不明顯。不過 越來越難找出問題所在當使用者轉動這類事件時,如何處理大小調整事件 如何將手機從直向改成橫向,或者怎麼避免手機磨損 萬一清單過長,可能就感到痛苦不堪?

正確的事物 TM

我們認為有足夠理由來制定參考資源 旨在說明如何以可重複使用的方式處理所有這些問題 並維持效能標準

因此我們將採用 3 種技術來達成目標:DOM 回收、懸浮微粒 以及捲動錨定標記

我們的示範案例將採用類似 Hangouts 的即時通訊視窗,在當中捲動 例如互通有無首先,我們需要透過即時對話管道 訊息。技術上,沒有任何無限捲動器真的 但可使用的資料量有限 也可能是他們可能的為求簡單起見 以及挑選訊息、作者以及偶爾附加圖片附件 也會隨機延遲的行為來變得更加類似 運作。

Chat 應用程式螢幕截圖

DOM 回收

DOM 回收技術利用未充分利用的 DOM 節點數量。 一般做法是改用已在畫面外已建立的 DOM 元素 建立新的叢集DOM 節點本身很便宜 ,因為它們都會增加記憶體、版面配置、風格和繪製成本。 而在低階裝置上,如果無法完全無法使用,這類裝置的運作速度會明顯變慢 網站的 DOM 過大,無法管理。此外請注意,每次重新版面配置 重新應用您的樣式 – 每次有類別時都會觸發的處理程序 會在節點上新增或移除時,如果使用較大的 DOM,就會增加費用。 回收 DOM 節點代表系統會保留 DOM 總數 大幅降低節點容量,讓所有程序都能更快完成。

第一種是捲動的過程,因為模型中 在 DOM 的所有可用項目中,我們必須找出其他方式 讓瀏覽器的捲軸正確反映 理論上我們將使用 1px x 1px 的 Sendinel 元素搭配 Transform 強制包含項目的元素,即跑道,取得所需的 。我們將把伸展過程的每個元素都推廣到各自的層, 確認跑道的圖層本身已完全空白。無背景顏色, 什麼都不做。如果伸展台的圖層為非空白,就不符合瀏覽器的 而且必須在圖形卡上儲存紋理,且 由幾十萬像素所組成絕對不適用於 使用行動裝置

每次捲動時,我們都會檢查可視區域是否接近 跑步訓練的尾聲如果有,我們會移動 Sentinel 來延長伸展台 元素,然後將離開可視區域的項目移到 並填入新內容。

跑道 Sentinel 可視區域

反向捲動也是如此。不過,我們不會 縮小實作中的跑道,讓捲軸的位置保持不變 保持一致

墓碑

如先前所述,我們嘗試讓資料來源的行為像 與現實世界的聯繫影響網路延遲和其他層面。也就是說, 使用者會利用閃爍的捲動功能, 大量資料如果發生這種情況,我們會放置空值標記項目 placeholder - 只有當 資料。也會回收 Tombstones,並擁有 可重複使用的 DOM 元素我們需要這麼做,才能在使用者 連至填入內容的項目,否則 讓他們感到不悅

這些
陵墓非常岩石。超酷的!

有趣的挑戰是,實際項目的高度可能比 因為每個項目或單一項目的文字數量不同 圖片。為解決這個問題,每次使用時,系統都會調整目前的捲動位置 然後以空值取代可視區域上方,錨定 捲動位置移至元素,而非像素值。這個概念 稱為「捲動錨定」

捲動錨定

以這種方式取代空值標記時,系統會同時叫用捲動錨定標記 以及視窗大小調整時 (如果裝置 請翻閱)。我們必須找出 檢視點由於該元素可能只能顯示部分,因此我們也會 儲存可視區域起始位置與元素頂端的偏移值。

捲動錨定圖表。

如果可視區域的大小經過調整且跑道有所變更,我們可將 感覺自己遇到的視覺上相同。勝利!不含已調整大小 表示每個項目的高度可能都已變更,因此該如何 判斷錨定內容應該放置多久?才不是!如要瞭解詳情 我們必須為錨定項目上方的每個元素設定版面配置,然後將所有元素相加 他們的高度;這可能會導致廣告調整大小時 那樣而是假設上述每個項目的大小都相同 做為空值,並據此調整捲動位置。由於 元素 捲動進入跑道時,我們會調整捲動位置,有效延後 版面配置會在實際需要時發揮作用

版面配置

我略過了一個重要細節:版面配置。每次回收 DOM 元素 通常會重新調整整個跑道的配置,這樣我們才不會偏離 目標是每秒 60 個影格為避免發生這個問題,我們將減輕 並搭配轉換,使用絕對位置元素。 如此一來,我們就能假定伸展台以外的所有元素 實際上會在實際運作時佔用空間。在我們做的事 就能快取每個項目最後出現的位置 當使用者向後捲動時,會立即從快取載入正確的元素。

在理想情況下,項目附加至 DOM 時,系統只會重新繪製一次 而且因為伸展台上的其他物品一起搬運或拆除,導致內容不多。也就是 但僅適用於新式瀏覽器

尖端的調整

最近,Chrome 開始支援 CSS 遏制功能 可讓開發人員告訴瀏覽器某個元素 繪製版面配置及繪製作品由於我們自己在這裡進行版面配置, 來遏止容器當每次在跑道中加入元素時,我們都會知道 其他項目就不需要受到重新版面配置的影響。因此每個項目 即可獲得 contain: layout。我們也不想影響網站的其他部分 因此跑道本身應該也會取得這個 style 指令。

另一項考量重點是 IntersectionObservers 做為偵測機制 使用者捲動畫面的時間夠長,讓我們開始回收元素並載入新的 資料。不過,IntersectionObserver 會指定為高延遲 (就像 使用 requestIdleCallback),因此實際的回應速度可能降低 IntersectionObserver。即使是目前導入的 scroll 事件會發生在這個問題,因為捲動事件會 「盡力而為」。最後,Houdini 的合成器小程式 才能解決這個問題

仍然不盡完美

目前的 DOM 回收實作會加入所有元素,因此並不理想 區域「傳遞」至可視區域,而不是只考量在 「位於」畫面上。也就是說,當您快速捲動畫面時 有太多難以跟 Chrome 的版面配置和繪製問題你將結束 只能看到背景又不是世界末日, 絕對值得改進

希望您能清楚看到,在日後需要面對的簡單問題時, 以便提供良好的使用者體驗和高效能標準。取代為 漸進式網頁應用程式成為手機的核心體驗 因此網頁程式開發人員必須 並遵循效能限制的模式

您可以在我們的存放區中找到所有程式碼。我們 我們會盡可能讓此程式庫可重複使用,但不會發布為實際資料庫 npm 或做為獨立的存放區使用。主要用途為教育性質。