摘要:百度搜索資源平臺有閃電算法的支持,為了能夠保障用戶體驗,給予優秀站點更多面向用戶的機會,閃電算法在年月初上線。下欄是每一個指標的細化性能評估。最后優化之路漫漫,永無止境,天下武功,唯快不破。
首屏作為直面用戶的第一屏,其重要性不言而喻,如何加快加載的速度是非常重要的一課。
本文講解的是:筆者對自己搭建的個人博客網站的速度優化的經歷。
效果體驗地址: http://biaochenxuying.cn
1. 用戶期待的速度體驗2018 年 8 月,百度搜索資源平臺發布的《百度移動搜索落地頁體驗白皮書 4.0 》中提到:頁面的首屏內容應在 1.5 秒內加載完成。
也許有人有疑惑:為什么是 1.5 秒內?哪些方式可加快加載速度?以下將為您解答這些疑問!
移動互聯網時代,用戶對于網頁的打開速度要求越來越高。百度用戶體驗部研究表明,頁面放棄率和頁面的打開時間關系如下圖所示:
根據百度用戶體驗部的研究結果來看,普通用戶期望且能夠接受的頁面加載時間在 3 秒以內。若頁面的加載時間過慢,用戶就會失去耐心而選擇離開,這對用戶和站長來說都是一大損失。
百度搜索資源平臺有 “閃電算法” 的支持,為了能夠保障用戶體驗,給予優秀站點更多面向用戶的機會,“閃電算法”在 2017 年 10 月初上線。
閃電算法 的具體內容如下:
移動網頁首屏在 2 秒之內完成打開的,在移動搜索下將獲得提升頁面評價優待,獲得流量傾斜;同時,在移動搜索頁面首屏加載非常慢(3 秒及以上)的網頁將會被打壓。
2. 分析問題未優化之前,首屏時間居然大概要 7 - 10 秒,簡直不要太鬧心。
開始分析問題,先來看下 network :
主要問題:
第一個文章列表接口用了 4.42 秒
其他的后端接口速度也不快
另外 js css 等靜態的文件也很大,請求的時間也很長
我還用了 Lighthouse 來測試和分析我的網站。
Lighthouse 是一個開源的自動化工具,用于改進網絡應用的質量。 你可以將其作為一個 Chrome 擴展程序運行,或從命令行運行。 為 Lighthouse 提供一個需要審查的網址,它將針對此頁面運行一連串的測試,然后生成一個有關頁面性能的報告。
未優化之前:
上欄內容分別是頁面性能、PWA(漸進式 Web 應用)、可訪問性(無障礙)、最佳實踐、SEO 五項指標的跑分。
下欄是每一個指標的細化性能評估。
再看下 Lighthouse 對性能問題給出了可行的建議、以及每一項優化操作預期會幫我們節省的時間:
從上面可以看出,主要問題:
圖片太大
一開始圖片就加載了太多
知道問題所在就已經成功了一半了,接下來便開始優化之路。
2. 優化之路網頁速度優化的方法實在太多,本文只說本次優化用到的方法。
2.1 前端優化本項目前端部分是用了 react 和 antd,但是 webpack 用的還是 3.8.X 。
2.1.1 webpack 打包優化因為 webpack4 對打包做了很多優化,比如 Tree-Shaking ,所以我用最新的 react-create-app 重構了一次項目,把項目升級了一遍,所有的依賴包都是目前最新的穩定版了,webpack 也升級到了 4.28.3 。
用最新 react-create-app 創建的項目,很多配置已經是很好了的,筆者只修改了兩處地方。
打包配置修改了 webpack.config.js 的這一行代碼:
// Source maps are resource heavy and can cause out of memory issue for large source files. const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; // 把上面的代碼修改為: const shouldUseSourceMap = process.env.NODE_ENV === "production" ? false : true;
生產環境下,打包去掉 SourceMap,靜態文件就很小了,從 13M 變成了 3M 。
還修改了圖片打包大小的限制,這樣子小于 40K 的圖片都會變成 base64 的圖片格式。
{ test: [/.bmp$/, /.gif$/, /.jpe?g$/, /.png$/,/.jpg$/,/.svg$/], loader: require.resolve("url-loader"), options: { limit: 40000, // 把默認的 10000 修改為 40000 name: "static/media/[name].[hash:8].[ext]", }, }2.1.2 去掉沒用的文件
比如之前可能覺得會有用的文件,后面發現用不到了,注釋或者刪除,比如 reducers 里面的 home 模塊。
import { combineReducers } from "redux" import { connectRouter } from "connected-react-router" // import { home } from "./module/home" import { user } from "./module/user" import { articles } from "./module/articles" const rootReducer = (history) => combineReducers({ // home, user, articles, router: connectRouter(history) })2.1.3 圖片處理
把一些靜態文件再用 photoshop 換一種格式或者壓縮了一下, 比如 logo 圖片,原本 111k,壓縮后是 23K。
首頁的文章列表圖片,修改為懶加載的方式加載。
之前因為不想為了個懶加載功能而引用一個插件,所以想自己實現,看了網上關于圖片懶加載的一些代碼,再結合本項目,實現了一個圖片懶加載功能,加入了 事件的節流(throttle)與防抖(debounce)。
代碼如下:
// fn 是事件回調, delay 是時間間隔的閾值 function throttle(fn, delay) { // last 為上一次觸發回調的時間, timer 是定時器 let last = 0, timer = null; // 將throttle處理結果當作函數返回 return function() { // 保留調用時的 this 上下文 let context = this; // 保留調用時傳入的參數 let args = arguments; // 記錄本次觸發回調的時間 let now = +new Date(); // 判斷上次觸發的時間和本次觸發的時間差是否小于時間間隔的閾值 if (now - last < delay) { // 如果時間間隔小于我們設定的時間間隔閾值,則為本次觸發操作設立一個新的定時器 clearTimeout(timer); timer = setTimeout(function() { last = now; fn.apply(context, args); }, delay); } else { // 如果時間間隔超出了我們設定的時間間隔閾值,那就不等了,無論如何要反饋給用戶一次響應 last = now; fn.apply(context, args); } }; } // 獲取可視區域的高度 const viewHeight = window.innerHeight || document.documentElement.clientHeight; // 用新的 throttle 包裝 scroll 的回調 const lazyload = throttle(() => { // 獲取所有的圖片標簽 const imgs = document.querySelectorAll("#list .wrap-img img"); // num 用于統計當前顯示到了哪一張圖片,避免每次都從第一張圖片開始檢查是否露出 let num = 0; for (let i = num; i < imgs.length; i++) { // 用可視區域高度減去元素頂部距離可視區域頂部的高度 let distance = viewHeight - imgs[i].getBoundingClientRect().top; // 如果可視區域高度大于等于元素頂部距離可視區域頂部的高度,說明元素露出 if (distance >= 100) { // 給元素寫入真實的 src,展示圖片 let hasLaySrc = imgs[i].getAttribute("data-has-lazy-src"); if (hasLaySrc === "false") { imgs[i].src = imgs[i].getAttribute("data-src"); imgs[i].setAttribute("data-has-lazy-src", true); // } // 前 i 張圖片已經加載完畢,下次從第 i+1 張開始檢查是否露出 num = i + 1; } } }, 1000);
注意:給元素寫入真實的 src 了之后,把 data-has-lazy-src 設置為 true ,是為了避免回滾的時候再設置真實的 src 時,瀏覽器會再請求這個圖片一次,白白浪費服務器帶寬。
具體細節請看文件 文章列表
2.2 后端優化后端用到的技術是 node、express 和 mongodb。
后端主要問題是接口速度很慢,特別是文章列表的接口,已經是分頁請求數據了,為什么還那么慢呢 ?
所以查看了接口返回內容之后,發現返回了很多列表不展示的字段內容,特別是文章內容都返回了,而文章內容是很大的,占用了很多資源與帶寬,從而使接口消耗的時間加長。
從上圖可以看出文章列表接口只要返回文章的 標題、描述、封面、查看數,評論數、點贊數和時間即可。
所以把不需要給前端展示的字段注釋掉或者刪除。
// 待返回的字段 let fields = { title: 1, // author: 1, // keyword: 1, // content: 1, desc: 1, img_url: 1, tags: 1, category: 1, // state: 1, // type: 1, // origin: 1, // comments: 1, // like_User_id: 1, meta: 1, create_time: 1, // update_time: 1, };
同樣對其他的接口都做了這個處理。
后端做了處理之后,所有的接口速度都加快了,特別是文章列表接口,只用了 0.04 - 0.05 秒左右,相比之前的 4.3 秒,速度提高了 100 倍,簡直不要太爽, 效果如下:
此刻心情如下:
2.3 服務器優化你以為前后端都優化一下,本文就完了 ?小兄弟,你太天真了,重頭戲在后頭 !
筆者服務器用了 nginx 代理。
做的優化如下:
隱藏 nginx 版本號
一般來說,軟件的漏洞都和版本相關,所以我們要隱藏或消除 web 服務對訪問用戶顯示的各種敏感信息。
如何查看 nginx 版本號? 直接看 network 的接口或者靜態文件請求的 Response Headers 即可。
沒有設置之前,可以看到版本號,比如我網站的版本號如下:
Server: nginx/1.6.2
設置之后,直接顯示 nginx 了,沒有了版本號,如下:
Server: nginx
開啟 gzip 壓縮
nginx 對于處理靜態文件的效率要遠高于 Web 框架,因為可以使用 gzip 壓縮協議,減小靜態文件的體積加快靜態文件的加載速度、開啟緩存和超時時間減少請求靜態文件次數。
筆者開啟 gzip 壓縮之后,請求的靜態文件大小大約減少了 2 / 3 呢。
gzip on; #該指令用于開啟或關閉gzip模塊(on/off) gzip_buffers 16 8k; #設置系統獲取幾個單位的緩存用于存儲gzip的壓縮結果數據流。16 8k代表以8k為單位,安裝原始數據大小以8k為單位的16倍申請內存 gzip_comp_level 6; #gzip壓縮比,數值范圍是1-9,1壓縮比最小但處理速度最快,9壓縮比最大但處理速度最慢 gzip_http_version 1.1; #識別http的協議版本 gzip_min_length 256; #設置允許壓縮的頁面最小字節數,頁面字節數從header頭得content-length中進行獲取。默認值是0,不管頁面多大都壓縮。這里我設置了為256 gzip_proxied any; #這里設置無論header頭是怎么樣,都是無條件啟用壓縮 gzip_vary on; #在http header中添加Vary: Accept-Encoding ,給代理服務器用的 gzip_types text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml text/javascript application/javascript application/x-javascript text/x-json application/json application/x-web-app-manifest+json text/css text/plain text/x-component font/opentype font/ttf application/x-font-ttf application/vnd.ms-fontobject image/x-icon; #進行壓縮的文件類型,這里特別添加了對字體的文件類型 gzip_disable "MSIE [1-6].(?!.*SV1)"; #禁用IE 6 gzip
把上面的內容加在 nginx 的配置文件 ngixn.conf 里面的 http 模塊里面即可。
是否設置成功,看文件請求的 Content-Encoding 是不是 gzip 即可。
設置 expires,設置緩存
server { listen 80; server_name localhost; location / { root /home/blog/blog-react/build/; index index.html; try_files $uri $uri/ @router; autoindex on; expires 7d; # 緩存 7 天 } }
我重新刷新請求的時候是 2019 年 3 月 16 號,是否設置成功看如下幾個字段就知道了:
Staus Code 里面的 form memory cache 看出,文件是直接從本地瀏覽器本地請求到的,沒有請求服務器。
Cache-Control 的 max-age= 604800 看出,過期時間為 7 天。
Express 是 2019 年 3 月 23 號過期,也是 7 天過期。
注意:上面最上面的用紅色圈中的 Disable cache 是否是打上了勾,打了勾表示:瀏覽器每次的請求都是請求服務器,無論本地的文件是否過期。所以要把這個勾去掉才能看到緩存的效果。3.1 測試場景終極大招:服務端渲染 SSR,也是筆者接下來的方向。
一切優化測試的結果脫離了實際的場景都是在耍流氓,而且不同時間的網速對測試結果的影響也是很大的。
所以筆者的測試場景如下:
a. 筆者的服務器是阿里的,配置是入門級的學生套餐配置,如下:
b. 測試網絡為 10 M 光纖寬帶。
3.2 優化結果優化之后的首屏速度是 2.07 秒。
最后加了緩存的結果為 0.388 秒。
再來看下 Lighthouse 的測試結果:
比起優化之前,各項指標都提升了很大的空間。
4. 最后優化之路漫漫,永無止境,天下武功,唯快不破。
本次優化的前端與后端項目,都已經開源在 github 上了,歡迎圍觀。
前端:https://github.com/biaochenxuying/blog-react
后端:https://github.com/biaochenxuying/blog-node
github 博客地址:https://github.com/biaochenxuying/blog
如果您覺得這篇文章不錯或者對你有所幫助,請給個贊或者星唄,你的點贊就是我繼續創作的最大動力。
對 全棧修煉 有興趣的朋友可以掃下方二維碼關注我的公眾號
我會不定期更新有價值的內容,長期運營。
關注公眾號并回復 福利 可領取免費學習資料,福利詳情請猛戳: Python、Java、Linux、Go、node、vue、react、javaScript
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102633.html
摘要:大家好,我是一行今天給大家聊聊一行在讀研里最成功的投資,那必然是鍵盤邊上的每一本技術書啦畢竟股票基金這種投資即使賺了錢,過段時間就得還回去,非常的神奇但是讀過的每一本技術書籍,都內化在手指上了,只要給個鍵盤,就能給它實 ...
摘要:這樣優化后我們最多進行次判斷即可,大大提高了代碼的性能。表達式的值具有離散性, 個人博客,點擊查看目錄,喜歡可以關注一下. 1.從[]==![]為true來剖析JavaScript各種蛋疼的類型轉換 2.吹毛求疵的追求優雅高性能JavaScript 李小龍說過:天下武功,無堅不摧,唯快不破.(真的說過嗎?)我想說的是:世間網站,完美體驗,唯快不破.(這個我承認我說過.) showImg...
摘要:寫在前面你是否在檢索千百萬級數據時為性能和速度而擔憂呢,即使優化了,創建了數據庫索引,還是不盡如人意呢下面就主要介紹如何集成是法國初創公司為你提供毫秒級的數據庫實時搜索服務,天下武功無堅不摧,唯快不破。本文基于,其他版本大同小異。 寫在前面 你是否在檢索千百萬級數據時為性能和速度而擔憂呢,即使優化了sql,創建了數據庫索引,還是不盡如人意呢?下面就主要介紹laravel如何集成Algo...
摘要:快杰云主機最新一代快杰云主機,整體計算性能提升內網包量最高可達萬單個支持最大外網帶寬存儲性能最高可達萬,延遲低至。憑借強大的性能,快杰云主機為海量數據運算高性能數據庫高并發網絡集群等場景帶來新一輪的創新性體驗。 隨著5G網絡、大數據、人工智能、物聯網等技術的快速發展,數據增長進入了空前的規模。如何實現海量數據的存儲、分析、交互,真正發揮數據的價值,已經成為企業新的挑戰,而算力就是其中最先需...
摘要:譯文地址譯唯快不破應用的個優化步驟前端的逆襲知乎專欄原文地址時過境遷,應用比以往任何時候都更具交互性。使用負載均衡方案我們在之前討論緩存的時候簡要提到了內容分發網絡。換句話說,元素的串形訪問會削弱負載均衡器以最佳形式 歡迎關注知乎專欄 —— 前端的逆襲歡迎關注我的博客,知乎,GitHub。 譯文地址:【譯】唯快不破:Web 應用的 13 個優化步驟 - 前端的逆襲 - 知乎專欄原文地...
閱讀 1988·2021-11-19 09:40
閱讀 1931·2021-09-28 09:36
閱讀 2279·2021-09-22 10:02
閱讀 2724·2019-08-30 14:00
閱讀 1948·2019-08-29 15:31
閱讀 2893·2019-08-29 15:11
閱讀 2905·2019-08-29 13:04
閱讀 1080·2019-08-27 10:55