Instagram網站性能優化之路:第三部分

近年來,Instagram發佈了許多功能-咱們推出了故事,過濾器,建立工具,通知和消息直遞,以及許多其餘功能和優化。 可是,隨着產品功能的增加,一個不幸的反作用是咱們的網絡性能開始降低。 在過去的一年中,咱們有意識地努力來改善這一情況。 到目前爲止,咱們的不懈努力已使Feed頁的加載時間累計提高了近50%。 這一系列博客文章將概述咱們爲實現這些改進所作的一些工做。前端

緩存優先

因爲咱們已經在頁面加載的儘量早的時間點將數據推送到客戶端,所以,將數據發送到客戶端的更快的惟一方法就是根本沒必要獲取或推送任何數據。promise

咱們可使用緩存優先渲染方法來實現,儘管這確實意味着咱們必須在短期內向用戶顯示陳舊的Feed數據信息。 經過這種方法,當頁面加載完畢後,咱們會當即向用戶顯示其先前的提要和故事的緩存副本,而後在可用時將其替換爲新數據。緩存

咱們使用Redux來管理instagram.com上的狀態,整體而言,咱們實現該方法的方式是將Redux存儲的子集存儲在客戶端上的indexedDB表中,而後在首次加載頁面時從新更新該存儲。 可是,因爲indexedDB訪問、服務器數據獲取、用戶交互三者間的異步特性,若是用戶在緩存數據上進行交互可能會存在問題。可是咱們依舊想確保這些交互仍做用於從服務器獲取的新狀態數據。bash

例如,若是咱們要以簡便的方式處理緩存,則可能會遇到如下問題:咱們開始同時從緩存和網絡加載,而且因爲已準備好緩存的數據,所以將其顯示給用戶。 而後,用戶點擊喜歡該帖子,可是一旦最新的網絡數據返回,它就會用一個副本覆蓋該帖子,該副本會丟失用戶對於緩存副本的操做(請參見下圖)。服務器

爲了解決此問題,咱們須要一種將交互應用於緩存狀態,同時還存儲了這些交互,以便之後能夠在服務器上的新狀態上重放它們。markdown

若是您之前曾經使用過Git或相似的源代碼控制系統,則此問題可能看起來很熟悉。 若是咱們將緩存的提要狀態視爲一個分支,而將服務器提要響應視爲主服務器,則咱們有效地要作的是執行一個變基操做,將本地分支中的提交(喜歡,評論等)應用到主分支。網絡

咱們作了如下設計:app

  • 在頁面加載時,咱們發送對新數據的請求(或等待其推送)
  • 建立Redux狀態的階段性子集
  • 在請求/推送未完成期間,咱們存儲全部調度的動做
  • 請求到達後,咱們會將操做與新數據以及全部待處理的操做一塊兒應用到暫存狀態
  • 提交暫存狀態後,咱們只需用暫存狀態替換當前狀態便可。

經過具備暫存狀態,能夠從新使用全部現有的reducer行爲。 它還使暫存狀態(具備最新數據)與當前狀態保持獨立。 另外,因爲分段是使用Redux實現的,所以咱們只須要調度操做便可使用它!異步

API

function stagingAction(
    key: string,
    promise: Promise<Action>,
): AsyncAction<State, Action>

function stagingCommit(key: string): AsyncAction<State, Action>
複製代碼

Staging API包括兩個主要函數: stagingAction & stagingCommit。async

stagingAction接受一個Promise,該Promise將解決要分派到暫存狀態的動做。 它初始化暫存狀態並跟蹤自初始化以來已調度的全部操做。 在源代碼控制的類比中,咱們能夠將其視爲建立本地分支,由於當新數據到達時,如今發生的任何操做都將排隊,並應用於暫存狀態。

stagingCommit將staging狀態提交到current狀態。 若是對暫存狀態的任何異步操做處於暫掛狀態,它將在提交以前等待。 這相似於源代碼管理中的變基,由於咱們將全部本地更改(來自緩存分支)應用在主服務器(服務器中的新數據)之上,使本地分支保持最新狀態。

爲了啓用staging,咱們用處理stagingCommit動做並將stage的動做應用於新狀態。 要使用全部這些,咱們只須要調度相關的動做,一切都將爲咱們處理。 例如,若是咱們要獲取一個新的feed並將其應用於暫存狀態,則能夠執行如下操做:

function fetchAndStageFeed() {
    return stagingAction(
        'feed',
        (async () => {
            const {data} = await fetchFeedTimeline();
            return {
                type: FEED_LOADED,
                ...data,
            };
        })(),
    );
}

// Fetches the new feed and stages it
store.dispatch(fetchAndStageFeed());

// any other actions dispatched until the stagingCommit action
// will be applied to the 'feed' staged state

// Commits staging to the current state
store.dispatch(stagingCommit('feed'));
複製代碼

對Feed和Stories功能同時使用緩存優先渲染功能,分別使顯示完成時間縮短了2.5%和11%,並經過本機iOS和Android Instagram應用提供了更好的用戶體驗。

靜待第四部分

在第四部分,咱們講介紹如何裁剪代碼大小,而且經過代碼大小和執行優化提高性能。

請關注奶爸碼農公衆號,第一時間得到最新信息。

『奶爸碼農』從事互聯網研發工做10+年,經歷IBM、SAP、陸金所、攜程等國內外IT公司,目前在美團負責餐飲相關大前端技術團隊,按期分享關於大前端技術、投資理財、我的成長的思考與總結

相關文章
相關標籤/搜索