[譯]無盡滾動的復(fù)雜度--來自Google大神的拆解

原文地址:https://developers.google.com/web/updates/2016/07/infinite-scroller
原文作者:Surma
譯者:王芃


摘要: 重用你的DOM元素以及刪除那些遠(yuǎn)離可視范圍的元素人乓。為延遲顯示的元素使用占位符言疗。這里是一個無盡滾動的演示代碼

無盡滾動在互聯(lián)網(wǎng)上到處都有應(yīng)用。Google Music的藝術(shù)家列表是一個,F(xiàn)acebook的時間線是一個,Tweeter的話題列表也是一個。當(dāng)你向下滾動,新的內(nèi)容就神奇的“無中生有”了贮竟。這是一個得到廣泛贊揚(yáng)的、非常好的用戶體驗较剃。

在這個無盡滾動背后的技術(shù)挑戰(zhàn)其實比它看上去要難咕别。當(dāng)你想做正確的事時,你遇到的問題是巨大的写穴。開始時是一些比較簡單的事情惰拱,比如在頁面尾部的鏈接是無法點擊的,因為內(nèi)容不斷的把它們“擠”走确垫。但是問題逐漸開始變得越來越難:當(dāng)用戶將手機(jī)從豎屏改為橫屏?xí)r你該如何處理 resize 事件弓颈?或者當(dāng)列表過長時你如何避免手機(jī)的卡頓?

正確的事

我們認(rèn)為有充分的理由來實現(xiàn)一個參考設(shè)計:在保證性能的基礎(chǔ)上删掀,以一個可復(fù)用的方式來解決這些問題翔冀。

我們將會使用3種技術(shù)來達(dá)成目標(biāo):DOM回收、墓碑和滾動錨定披泪。

我們的demo會是一個類似聊天的窗口纤子,我們可以滾動這些消息列表。首先需要的是一個無盡的消息數(shù)據(jù)源款票。從技術(shù)角度看控硼,沒有任何一個無盡列表是真正無盡的,但當(dāng)有足夠的數(shù)據(jù)量填充進(jìn)去時艾少,它們看上去感覺是無盡的卡乾。為簡化問題,我們這里硬編碼了一套消息數(shù)據(jù)缚够,隨機(jī)的抽取消息幔妨、聯(lián)系人和圖片。為了更像網(wǎng)絡(luò)的真實情況谍椅,我們?nèi)藶榧尤肓艘恍┭舆t误堡。

image_1b8s8bm77scgbh31ill1qn41h199.png-786kB
image_1b8s8bm77scgbh31ill1qn41h199.png-786kB

DOM 回收

DOM回收是一個未被廣泛使用的技術(shù),它的用途是讓DOM的節(jié)點數(shù)保持在較低的數(shù)值雏吭。概括來說锁施,它的機(jī)制是利用那些離開視圖區(qū)域的、已經(jīng)創(chuàng)建的DOM元素,而不是新建DOM元素悉抵。需要承認(rèn)的一點是DOM節(jié)點本身并非耗能大戶肩狂,但是也不是一點都不消耗性能,每一個節(jié)點都會增加一些額外的內(nèi)存基跑、布局婚温、樣式和繪制。如果一個站點的DOM節(jié)點過多媳否,在低端設(shè)備上會發(fā)現(xiàn)明顯的變慢,如果沒有徹底卡死的話荆秦。同樣需要注意的一點是篱竭,在一個較大的DOM中每一次重新布局或重新應(yīng)用樣式(在節(jié)點上增加或刪除樣式所觸發(fā)的過程)的系統(tǒng)開銷都會比較昂貴。所以進(jìn)行DOM回收意味著我們會保持DOM節(jié)點在一個比較低的數(shù)量上步绸,進(jìn)而加快上面提到的這些處理過程掺逼。

第一個障礙是滾動本身。由于我們在任何時刻DOM中只有全部列表項目的一個微小子集瓤介,我們需要找到一種方式可以讓瀏覽器正確的反映出理論上應(yīng)該在“那里”的全部列表項目數(shù)量吕喘。我們這里用一個 1px * 1px 的”前哨“元素(sentinel),并且應(yīng)用一個變換使得包含“逃兵”列表項目的元素(下圖中的 runway)保持一個理想的高度刑桑。我們會把runaway中的每一個元素提升到它們自己的層氯质,保持 runaway 本身是完全空的,沒有背景色祠斧,神馬都木有闻察。如果 runaway層不是空的話,是不利于瀏覽器優(yōu)化的琢锋。因為我們將不得不在顯卡上存儲一個由成千上萬的像素組成的紋理辕漂。這樣做顯然在移動設(shè)備上是不可行的。

當(dāng)我們進(jìn)行滾動時吴超,我們會檢查是否viewport是否已經(jīng)足夠接近 runaway 的尾部钉嘹。如果是的話,我們會通過把 sentinel和viewport中的剩余元素移向 runaway的底部來擴(kuò)展 runaway鲸阻,然后用新內(nèi)容渲染這些元素跋涣。

向反方向滾動時也類似,但我們無論如何也不會縮小 runaway赘娄,原因是我們需要滾動欄的位置保持連續(xù)性仆潮。

墓碑(Tombstones)

如之前我們所說,我們會盡量讓數(shù)據(jù)源表現(xiàn)的像現(xiàn)實世界遇到的情況:有網(wǎng)絡(luò)延遲及其它情況遣臼。這就意味著如果我們的用戶飛快地滾動性置,他們會很容易就把我們渲染的有數(shù)據(jù)的項目都甩在身后。如果這種情況發(fā)生時揍堰,我們就需要放置一個墓碑條目(占位)在對應(yīng)位置鹏浅,等到數(shù)據(jù)取到后墓碑條目會被實際內(nèi)容替代嗅义。墓碑也會被回收,對于墓碑元素會有一個獨(dú)立的可復(fù)用DOM元素的池隐砸。這樣設(shè)計的原因是之碗,我們希望墓碑元素在被實際數(shù)據(jù)替代時可以有一個漂亮的過渡,而不是出現(xiàn)那種生硬的或者讓人迷失的效果季希。

墓碑元素
墓碑元素

這里有一個有趣的挑戰(zhàn)褪那,那就是真實的條目的高度可能會超過墓碑的高度,因為不同的文本量或者圖片的大小決定了這點式塌。為了解決這個問題博敬,每次當(dāng)取到數(shù)據(jù)后我們會調(diào)整當(dāng)前的滾動位置,而且在viewport之上的一個墓碑條目也會被替換峰尝。將滾動位置錨定到某一條目而非某一具體的像素位置偏窝,這個概念叫做滾動錨定。

滾動錨定

滾動錨定的觸發(fā)時機(jī)有兩個:一個是墓碑被替換時武学,另一個是窗口大小發(fā)生改變時(在設(shè)備發(fā)生翻轉(zhuǎn)時也會發(fā)生)祭往。我們必須要知道在viewport中的最頂部可見元素是什么。由于這個元素可能只是部分可見的火窒,所以我們也需要存儲從頂部元素到viewport頂部的偏移量硼补。

滾動錨定
滾動錨定

這樣的話,當(dāng)viewport改變大小時沛鸵、runaway 改變時括勺,我們是可以把場景恢復(fù)到一個看起來和原來幾乎一致的樣子。爽就一個字曲掰!但是改變大小的視窗意味著每個條目都可能改變了高度疾捍,那么我們?nèi)绾文苤涝摪彦^定的內(nèi)容移動多少偏移量呢?我們并不知道栏妖!為了搞清楚這點乱豆,我們可能不得不把錨定條目之上的元素布局起來,把它們的高度累加在一起吊趾。但顯然這樣做會造成改變大小時會有明顯的停頓宛裕,我們并不想要這樣的結(jié)果。相反论泛,我們借助于一個假設(shè):在viewport之上的每個元素都是和墓碑等高的揩尸。根據(jù)這個假設(shè)來調(diào)整對應(yīng)的滾動位置。當(dāng)元素滾動進(jìn)入 runaway 時屁奏,我們調(diào)整滾動位置岩榆,這樣就有效的把布局工作延遲到真正需要的時候了。

布局

我剛才跳過了一個重要的細(xì)節(jié):布局。每次DOM元素的回收通常情況下都會引發(fā)整個 runaway 的重新布局勇边,這會直接影響我們的性能:無法達(dá)成每秒60幀的目標(biāo)犹撒。為避免這一點,我們自己承擔(dān)了布局的重任粒褒,使用了絕對定位的元素识颊。這樣我們可以讓所有 runaway 中的元素感覺上還在占用空間,但其實那里毛都沒有奕坟。由于我們自己在操控布局祥款,我們便可以緩存每個元素消失前的位置,在用戶往回滾動時执赡,我們能立刻從緩存中加載正確的元素镰踏。

理想情況下,條目應(yīng)該只被重繪一次沙合,那就是當(dāng)它們被加到DOM時。而且應(yīng)該對于 runaway 中其它條目的增加或刪除完全不受影響跌帐。這個是可能的首懈,但是只限于現(xiàn)代瀏覽器。

極致優(yōu)化

最近谨敛,Chrome增加了CSS Containment的支持究履,這個特性允許開發(fā)者告訴瀏覽器某個元素是布局和繪制的邊界。由于我們這里采用的是自己來布局脸狸,這是一個很好的可以應(yīng)用 containment 的機(jī)會最仑。當(dāng)我們增加一個元素到 runaway時,我們知道其它條目不應(yīng)該被這個重新布局影響炊甲。所以每個條目應(yīng)該設(shè)置一個 contain: layout泥彤。我們同樣也不希望影響站點的其它部分,所以 runaway 本身也需要這樣設(shè)置卿啡。

另一個優(yōu)化點吟吝,我們考慮的是利用IntersectionObservers去檢測用戶是否已經(jīng)滾動了足夠距離,以便于我們決定是否開始回收DOM和加載新數(shù)據(jù)颈娜。但是 IntersectionObservers 是為高延遲設(shè)計的剑逃,所以我們實際上會“感覺”用了 IntersectionObservers 反而比不用時“響應(yīng)更慢”。在我們當(dāng)前的實現(xiàn)中滾動事件的處理其實也存在這個問題官辽。也許這個問題的可信度較高的解決方案會是 Houdini’s Compositor Worklet

仍不完美

目前的DOM回收實現(xiàn)方式仍不是完美的蛹磺,因為我們把所有“滾過”viewport的元素都添加到DOM了,而不是僅僅關(guān)心那些在屏幕上可見的元素同仆。這就意味著萤捆,如果你滾動的真的非常非常快的話,快到你堆積了大量的布局和繪制工作鳖轰,瀏覽器已經(jīng)無法跟上的地步時清酥,這時我們可能除了背景什么都看不到了。這當(dāng)然不是世界末日但是確實是一個可以優(yōu)化的地方蕴侣。

我們希望你可以看到這個過程:當(dāng)你想提供一個高性能的有良好用戶體驗的功能時焰轻,一個簡單的問題是演變成復(fù)雜問題的。隨著“Progressive Web Apps ”逐漸成為移動設(shè)備的一等公民昆雀,高性能的良好體驗會變得越來越重要辱志,開發(fā)者也必須持續(xù)的研究使用一些模式來應(yīng)對性能約束。

所有的代碼可以到這里查看狞膘,我們已經(jīng)盡力讓代碼有可復(fù)用性了揩懒,但不會發(fā)布一個npm類庫或其它單獨(dú)的項目。這個代碼的主要目的是教學(xué)挽封。

慕課網(wǎng) Angular 視頻課上線: http://coding.imooc.com/class/123.html?mc_marking=1fdb7649e8a8143e8b81e221f9621c4a&mc_channel=banner

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末已球,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辅愿,更是在濱河造成了極大的恐慌智亮,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件点待,死亡現(xiàn)場離奇詭異阔蛉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)癞埠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門状原,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苗踪,你說我怎么就攤上這事颠区。” “怎么了徒探?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵瓦呼,是天一觀的道長。 經(jīng)常有香客問我测暗,道長央串,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任碗啄,我火速辦了婚禮质和,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稚字。我一直安慰自己饲宿,他們只是感情好厦酬,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘫想,像睡著了一般辉阶。 火紅的嫁衣襯著肌膚如雪褥蚯。 梳的紋絲不亂的頭發(fā)上至壤,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天厦凤,我揣著相機(jī)與錄音,去河邊找鬼车吹。 笑死筹裕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的窄驹。 我是一名探鬼主播朝卒,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乐埠!你這毒婦竟也來了抗斤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤丈咐,失蹤者是張志新(化名)和其女友劉穎豪治,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扯罐,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年烦衣,在試婚紗的時候發(fā)現(xiàn)自己被綠了歹河。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡花吟,死狀恐怖秸歧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衅澈,我是刑警寧澤键菱,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站今布,受9級特大地震影響经备,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜部默,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一侵蒙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧傅蹂,春花似錦纷闺、人聲如沸算凿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氓轰。三九已至,卻和暖如春浸卦,著一層夾襖步出監(jiān)牢的瞬間署鸡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工镐躲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留储玫,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓萤皂,卻偏偏與公主長得像撒穷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子裆熙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案端礼? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,748評論 1 92
  • 1. 介紹 瀏覽器可能是最廣泛使用的軟件。本書將介紹瀏覽器的工作原理入录。我們將看到蛤奥,當(dāng)你在地址欄中輸入google....
    康斌閱讀 2,018評論 7 18
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,070評論 25 707
  • 一個人在生活中可能有太多的不順心和太多的誘惑,樂極生悲和痛不欲生的人我們實在看得太多了僚稿。雖然僅二十余歲凡桥,但...
    紅發(fā)香克斯_閱讀 181評論 0 0
  • 細(xì)雨過后,一時的興致?lián)沃愎淦鹆讼嗵幜巳甑男@蚀同。一時迎來周圍人數(shù)雙巡視的目光缅刽。應(yīng)該是很久沒見過這么充滿童趣的學(xué)...
    趙凡一閱讀 358評論 3 5