移動端H5活動頁優化方案

来源:https://www.cnblogs.com/liuyongjia/archive/2018/04/06/8728900.html
-Advertisement-
Play Games

背景 項目 :移動端H5電商項目 痛點 :慢!!! 初始方案 :最基本的圖片懶載入,靜態資源放到cdn,predns等等已經都做了。但是還是慢,慢在哪? 顯而易見的原因 :由於前後端分離,所有的數據都由介面下發,之後根據模板渲染頁面。也就是說,我們需要先載入js,等到js載入完畢之後,請求介面,介面 ...


背景

項目:移動端H5電商項目
痛點:慢!!!
初始方案:最基本的圖片懶載入,靜態資源放到cdn,predns等等已經都做了。但是還是慢,慢在哪?
顯而易見的原因:由於前後端分離,所有的數據都由介面下發,之後根據模板渲染頁面。也就是說,我們需要先載入js,等到js載入完畢之後,請求介面,介面返回數據之後,渲染頁面,載入圖片等等。儘管使用了模塊化的載入方式,但是對於要求高的首頁和活動頁,給用戶的感知也不是很好。

初版解決方案

最初,由於時間緊迫,基本上都是從客戶端作優化處理,基本上可以總結為以下幾個方面。

一、本地緩存

我們做了本地緩存優化的策略,第一次請求之後就把介面數據緩存到localStorage裡面,並且存儲當時的時間,設定過期時間,一般設置為5分鐘,用戶在5分鐘內重覆打開頁面,不會再次請求介面,從localstorage中拿取數據,直接渲染頁面。
後續乾脆把模板渲染好的html片段存儲了起來,直接拼接,省去了模板計算的時間。
基本實現方案如下:

var 
    cache = localStorage.getItem('cache')
    , expires = 5 * 60 * 1000
;

// 判斷是否過期
function isOverdue(pastTime, expires) {
    return Date.now() - pasttime >= expires;
}

if (cache && !isOverdue(cache.time, expires)) {
    // 說明緩存存在,並且沒有過期
    // 就正常取cache.data做相應的渲染
} else {
    // 說明緩存不存在或者已經過期了
    // 重新請求介面
    $.get('a.cn', funciton (res) {
        // do something
        // 把對應的渲染操作處理完成之後,將數據緩存,並記錄當前的時間
        localStorage.setItem('cache', {
            data: res,
            time: Date.now()
        })
    })
} 

然而還是不夠,新用戶在首次打開時,還是不能秒開頁面,並且用戶在5分鐘之後重新載入之時,仍然會有一定的延遲(由於瀏覽器會緩存一部分靜態資源,此時再打開並不會像用戶初次打開一樣那麼慢)。

二、進一步緩存靜態資源

在日常開發中,有很多依賴庫,常用的fastclick,swipe等等,這些庫,沒有必要每次都去載入,雖然瀏覽器會對一些靜態資源做緩存,但是卻不能完全被我們控制,所以,可以將這些不常發生變化的靜態資源緩存起來,同樣的,存到localStorage裡面。

需要註意

這個方案有一個問題,如果是直接載入的script標簽,是無法直接拿到它的腳本內容的。

<script id="script1" src="js/jquery.js"></script>
console.log(document.querySelector('#script1').innerHTML);
// 此時輸出的是undefined,因為innerHTML是獲取標簽內容,此時script標簽里並沒有內容。
<script id="script2">
console.log('2');
</script>
console.log(document.querySelector('#script2').innerHTML);
// 此時輸出的是console.log('2');
// 因為innerHTML是獲取標簽內容,此時script標簽里並沒有內容。

這當然不是我們想要的,我們需要的是外鏈js的可執行代碼。

動態添加js的兩種方案

我在前一篇高性能JavaScript讀書筆記中提到了兩種方案。

1. 動態腳本元素

var script = document.createElement('script');
script.type = 'text/javascript';
script.onload = function () {
    // do something
}
script.src = 'jquery.js';
document.getElementByTagName('heda')[0].appendChild(script);

這種方法可以監控到腳本的完成事件,但是由於也是通過添加一個script標簽,並不能拿到我們想要的js代碼。

2. 通過XMLHttPRequest腳本註入

var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
            localStorage.setItem('file1', xhr.responseText);
        }
    }
}

需要特別註意的是,這個方法有跨域的風險,所以,我們需要靜態資源伺服器的allow-origin設置為*。或者直接載入本功能變數名稱下的js。

有同學要問了,既然localStorage這麼強大,為什麼不把所有的東西都緩存起來呢?
當然是因為它的大小有限制,在FireFox和chrome中,一般來說,sessionStorage和localStorage大小為10MB,而safari只有5MB。詳見這篇文章
這就限制了我們什麼都存的想法。如果圖片較小,可以緩存起來。

第二版解決方案

在前一版方案里,我們解決了後續載入的速度緩慢問題,在後續的頁面打開速度上,基本上可以做到秒開。
但是這個方案還是有不足,對於新用戶的體驗不是很好,如果用戶在5min的這個時間點上打開,速度還是會有所下降。
最後還是只能做SSR。
知乎上有一個問題,為什麼現在又流行服務端渲染html?
服務端渲染有很多好處,對我們此時而言,最大的好處就是頁面直出。省去了請求介面這一步操作。並且對於提高用戶體驗上來說,很有好處。
如果時間充裕,可以使用node做服務端,但是由於歷史原因,我們這個項目遷移起來也比較費時間,所以最後決定使用openresty來做。
openResty的教程網上很多了,我也不多說,除了官方git,推薦開濤博客學習。

不論我們是在客戶端取介面數據,還是服務端,活動頁的數據一般來說都有一定持續時長,也就是說,我們也可以在我們的nginx伺服器上做一個緩存,假設有一個用戶訪問了一個活動,那麼在接下來的五分鐘之內,其他任何用戶(相同許可權下)訪問到的就是第一個用戶訪問時緩存好的頁面。

local args = ngx.req.get_uri_args()
local acId = args['acId']
local key = 'ac' .. acId
local expire = 5 * 60 --緩存時間5分鐘

local value = dict.getData(key, expire)

if not value then
    local res = ngx.location.capture('/a.json')

    if res.status == 200 then
        -- dict是一個用來處理存儲和讀取邏輯的腳本
        dict.setData(key, res.body)
    else
        ngx.say(dict.getData(key))
    end
else
    --  ngx.log(4, type(value))
    ngx.say(value)
end

在dict中,我們可以把介面數據轉換成通過模板轉換為html片段存儲起來。這樣,用戶在第一次進入我們的頁面以後,也不會感覺慢了。

what's more

openResty能做的事不僅僅是這些,一些網關上許可權的控制等等都可以用它來實現。
上面兩個方案還有一些不足之處,比如首屏可能內容比較多,一次都載入過來,不一定會快。直觀的首屏的由服務端渲染,對於不重要的內容,可以通過AJAX來非同步載入。
如何計算活動頁這樣的頁面中,首屏有多大,如何組織代碼,哪些部分採用服務端渲染,哪些採用AJAX。這些問題在實際開發中也需要考慮。
限於時間,此次沒有能比較完善的解決這個問題,在日後開發中,還會繼續完善活動頁優化方案。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 開題:之前就有所耳聞,最近兩天第一次運用到圖標字體。剛開始嘛,一臉懵逼的狀態。成功運用之後就來記錄一下使用過程咯! 1. 打開線上生成工具:https://icomoon.io/app/#/select 2. 導入本地文件或者選擇圖標庫 (1) 如果你本地沒有.svg圖標,你可以選擇線上免費的圖標。 ...
  • Nodejs設計的核心理念:1.事件迴圈;2.模式;3.差錯處理;4.運用多處理器 ...
  • 時間關係長話短說,今天把文章編輯和刪除功能實現了。 本來是要單獨做兩個按鈕來選擇列表中的所有朋友圈文章,但是老師想偷懶……所以我也就跟著偷懶了。 編輯文章部分,可以獲取每條朋友圈的標題和內容。 第一步編輯的時候要打開編輯框,改動之後再保存至資料庫。 測試刪除這條數據。 有一個刪除的提示,也是用的el ...
  • 1)基礎 學習目的: 1. 客戶端表單驗證 2. 頁面動態效果 3. jQuery的基礎 什麼是JavaScript? 一種描述性語言,也是一種基於對象和事件驅動的,並具有安全性能的腳本語言 javaScript是一種基於對象和事件驅動的,並具有安全性能的腳本語言 解釋執行javaScript特點向 ...
  • 定義: 保證一個對象(類)僅有一個實例,並提供一個訪問它的全局訪問點; 實現原理: 利用閉包來保持對一個局部變數的引用,這個變數保存著首次創建的唯一的實例; 主要用於: 全局緩存、登錄浮窗等只需要唯一一個實例的時候; Part1、命名空間的管理員開發中經常會遇到不同的人定義的變數使用的單詞可能會重覆 ...
  • display的所有屬性 下麵就display的重要屬性進行講解,並配合一些相關的例子 基本屬性 display: none none 是 CSS 1 就提出來的屬性,將元素設置為none的時候既不會占據空間,也無法顯示,相當於該元素不存在。 該屬性可以用來改善重排與重繪,同時我也經常用它來做模態窗 ...
  • 使用遞歸函數必須要符合兩個條件: 1、 在每一次調用自己時,必須是(在某種意義上)更接近於解; 這句話怎麼理解? 大家家裡都有樓梯吧?比如從一樓走到二樓,那麼我們的起點是一樓,目的地是二樓,當你往上每走一個臺階是不是越接近二樓,也就是越接近目的地。 因此這句話可以這樣理解:函數每一次調用自己時... ...
  • 在 JavaScript 中 this 常常指向方法調用的對象,但有些時候並不是這樣的,本文將詳細解讀在不同的情況下 this 的指向。 一、指向 window: 在全局中使用 this,它將會指向全局對象,因為瀏覽器中運行的 JavaScript 的全局對象預設為 window, 所以,此時 ... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...