小說系統開發中,值得一看的效能優化重點

雲豹科技程式設計師發表於2021-12-08
效能優化時一個老生常談的話題,但是在小說系統開發過程中,為了提升使用者的使用體驗,我們又不得不重視,今天我們就一起來看看在小說系統開發中,那些值得一看的效能優化重點吧。

1、將 CSS 放在檔案頭部,JavaScript 檔案放在底部

  • CSS 執行會阻塞渲染,阻止 JS 執行
  • JS 載入和執行會阻塞 HTML 解析,阻止 CSSOM 構建
如果在小說系統開發中,這些 CSS、JS 標籤放在 HEAD 標籤裡,並且需要載入和解析很久的話,那麼頁面就空白了。所以 JS 檔案要放在底部(不阻止 DOM 解析,但會阻塞渲染),等 HTML 解析完了再載入 JS 檔案,儘早向使用者呈現頁面的內容。
那為什麼 CSS 檔案還要放在頭部呢?
因為先載入 HTML 再載入 CSS,會讓使用者第一時間看到小說系統開發的頁面是沒有樣式的、“醜陋”的,為了避免這種情況發生,就要將 CSS 檔案放在頭部了。 另外,JS 檔案也不是不可以放在頭部,只要給 script 標籤加上 defer 屬性就可以了,非同步下載,延遲執行。

2、使用字型圖示 iconfont 代替圖片圖示

小說系統開發中的字型圖示就是將圖示製作成一個字型,使用時就跟字型一樣,可以設定屬性,例如 font-size、color 等等,非常方便。並且字型圖示是向量圖,不會失真。還有一個優點是生成的檔案特別小。
壓縮字型檔案
使用 fontmin-webpack 外掛對字型檔案進行壓縮。
小說系統開發中,值得一看的效能優化重點

3、善用快取,不重複載入相同的資源

在小說系統開發中,為了避免使用者每次訪問網站都得請求檔案,我們可以通過新增 Expires 或 max-age 來控制這一行為。Expires 設定了一個時間,只要在這個時間之前,瀏覽器都不會請求檔案,而是直接使用快取。而 max-age 是一個相對時間,建議使用 max-age 代替 Expires 。 不過這樣會產生一個問題,當小說系統開發中檔案更新了怎麼辦?怎麼通知瀏覽器重新請求檔案? 可以通過更新頁面中引用的資源連結地址,讓瀏覽器主動放棄快取,載入新資源。 具體做法是把資源地址 URL 的修改與檔案內容關聯起來,也就是說,只有檔案內容變化,才會導致相應 URL 的變更,從而實現檔案級別的精確快取控制。什麼東西與檔案內容相關呢?我們會很自然的聯想到利用資料摘要要演算法對檔案求摘要資訊,摘要資訊與檔案內容一一對應,就有了一種可以精確到單個檔案粒度的快取控制依據了。

4、壓縮檔案

在小說系統開發時壓縮檔案可以減少檔案下載時間,讓使用者體驗性更好。 得益於 webpack 和 node 的發展,現在壓縮檔案已經非常方便了。 在 webpack 可以使用如下外掛進行壓縮:
  • JavaScript:UglifyPlugin
  • CSS :MiniCssExtractPlugin
  • HTML:HtmlWebpackPlugin
其實,我們還可以做得更好。那就是在小說系統開發中使用 gzip 壓縮。可以通過向 HTTP 請求頭中的 Accept-Encoding 頭新增 gzip 標識來開啟這一功能。當然,伺服器也得支援這一功能。 gzip 是目前最流行和最有效的壓縮方法。舉個例子,我用 Vue 開發的專案構建後生成的 app.js 檔案大小為 1.4MB,使用 gzip 壓縮後只有 573KB,體積減少了將近 60%。 附上 webpack 和 node 配置 gzip 的使用方法。
下載外掛
npm install compression-webpack-plugin --save-dev
npm install compression
webpack 配置
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
  plugins: [new CompressionPlugin()],
}
node 配置
const compression = require('compression')
// 在其他中介軟體前使用
app.use(compression())

5、圖片優化

(1). 圖片延遲載入
在小說系統開發的頁面中,先不給圖片設定路徑,只有當圖片出現在瀏覽器的可視區域時,才去載入真正的圖片,這就是延遲載入。對於圖片很多的網站來說,一次性載入全部圖片,會對使用者體驗造成很大的影響,所以需要使用圖片延遲載入。 首先可以將圖片這樣設定,在頁面不可見時圖片不會載入:
<img data-src="
等頁面可見時,使用 JS 載入圖片:
const img = document.querySelector('img')
img.src = img.dataset.src
這樣圖片就載入出來了,完整的程式碼可以看一下參考資料。
(2). 響應式圖片
在小說系統開發中,響應式圖片的優點是瀏覽器能夠根據螢幕大小自動載入合適的圖片。
通過 picture 實現
<picture>
	<source srcset="banner_w1000.jpg" media="(min-width: 801px)">
	<source srcset="banner_w800.jpg" media="(max-width: 800px)">
	<img src="banner_w800.jpg" alt="">
</picture>
通過 @media 實現
@media (min-width: 769px) {
	.bg {
		background-image: url(bg1080.jpg);
	}
}
@media (max-width: 768px) {
	.bg {
		background-image: url(bg768.jpg);
	}
}
(3). 調整圖片大小
例如,小說系統開發中有一個 1920* 1080 大小的圖片,用縮圖的方式展示給使用者,並且當使用者滑鼠懸停在上面時才展示全圖。如果使用者從未真正將滑鼠懸停在縮圖上,則浪費了下載圖片的時間。 所以,我們可以用兩張圖片來實行優化。一開始,只載入縮圖,當使用者懸停在圖片上時,才載入大圖。還有一種辦法,即對大圖進行延遲載入,在所有元素都載入完成後手動更改大圖的 src 進行下載。
(4). 降低圖片質量
例如 JPG 格式的圖片,100% 的質量和 90% 質量的通常看不出來區別,尤其是用來當小說系統開發背景圖的時候。我經常用 PS 切背景圖時, 將圖片切成 JPG 格式,並且將它壓縮到 60% 的質量,基本上看不出來區別。 壓縮方法有兩種,一是通過 webpack 外掛 image-webpack-loader,二是通過線上網站進行壓縮。 以下附上 webpack 外掛 image-webpack-loader 的用法。
npm i -D image-webpack-loader
webpack 配置
{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000, /* 圖片大小小於1000位元組限制時會自動轉成 base64 碼引用*/
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    /*對圖片進行壓縮*/
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
}
(5). 儘可能利用 CSS3 效果代替圖片
小說系統開發中有很多圖片使用 CSS 效果(漸變、陰影等)就能畫出來,這種情況選擇 CSS3 效果更好。因為程式碼大小通常是圖片大小的幾分之一甚至幾十分之一。
(6). 使用 webp 格式的圖片
WebP 的優勢體現在它具有更優的影像資料壓縮演算法,能帶來更小的圖片體積,而且擁有肉眼識別無差異的影像質量;同時具備了無損和有損的壓縮模式、Alpha 透明以及動畫的特性,在 JPEG 和 PNG 上的轉化效果都相當優秀、穩定和統一。

6、通過 webpack 按需載入程式碼,提取第三庫程式碼,減少 ES6 轉為 ES5 的冗餘程式碼

懶載入或者按需載入,是一種很好的優化小說系統開發的方式。這種方式實際上是先把你的程式碼在一些邏輯斷點處分離開,然後在一些程式碼塊中完成某些操作後,立即引用或即將引用另外一些新的程式碼塊。這樣加快了應用的初始載入速度,減輕了它的總體體積,因為某些程式碼塊可能永遠不會被載入。
根據檔案內容生成檔名,結合 import 動態引入元件實現按需載入 通過配置 output 的 filename 屬性可以實現這個需求。filename 屬性的值選項中有一個 [contenthash],它將根據檔案內容建立出唯一 hash。當檔案內容發生變化時,[contenthash] 也會發生變化。
output: {
	filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].js',
    path: path.resolve(__dirname, '../dist'),
},
提取第三方庫
由於引入的第三方庫一般都比較穩定,不會經常改變。所以將它們單獨提取出來,作為長期快取是一個更好的選擇。 這裡需要使用 webpack4 的 splitChunk 外掛 cacheGroups 選項。
optimization: {
  	runtimeChunk: {
        name: 'manifest' // 將 webpack 的 runtime 程式碼拆分為一個單獨的 chunk。
    },
    splitChunks: {
        cacheGroups: {
            vendor: {
                name: 'chunk-vendors',
                test: /[\\/]node_modules[\\/]/,
                priority: -10,
                chunks: 'initial'
            },
            common: {
                name: 'chunk-common',
                minChunks: 2,
                priority: -20,
                chunks: 'initial',
                reuseExistingChunk: true
            }
        },
    }
},
  • test:用於控制小說系統開發中哪些模組被這個快取組匹配到。原封不動傳遞出去的話,它預設會選擇所有的模組。可以傳遞的值型別:RegExp、String和Function;
  • priority:表示抽取權重,數字越大表示優先順序越高。因為一個 module 可能會滿足多個 cacheGroups 的條件,那麼抽取到哪個就由權重最高的說了算;
  • reuseExistingChunk:表示是否使用已有的 chunk,如果為 true 則表示如果當前的 chunk 包含的模組已經被抽取出去了,那麼將不會重新生成新的。
  • minChunks(預設是1):在分割之前,這個程式碼塊最小應該被引用的次數(譯註:保證程式碼塊複用性,預設配置的策略是不需要多次引用也可以被分割)
  • chunks (預設是async) :initial、async和all
  • name(打包的chunks的名字):字串或者函式(函式可以根據條件自定義名字)
減少 ES6 轉為 ES5 的冗餘程式碼
Babel 轉化後的程式碼想要實現和原來程式碼一樣的功能需要藉助一些幫助函式,比如:
class Person {}
會被轉換為:
"use strict";
function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}
var Person = function Person() {
  _classCallCheck(this, Person);
};
這裡 _classCallCheck 就是一個 helper 函式,如果在小說系統開發的很多檔案裡都宣告瞭類,那麼就會產生很多個這樣的 helper 函式。 這裡的 @babel/runtime 包就宣告瞭所有需要用到的幫助函式,而 @babel/plugin-transform-runtime 的作用就是將所有需要 helper 函式的檔案,從 @babel/runtime包 引進來:
"use strict";
var _classCallCheck2 = require("@babel/runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}
var Person = function Person() {
  (0, _classCallCheck3.default)(this, Person);
};
這裡就沒有再編譯出 helper 函式 classCallCheck 了,而是直接引用了 @babel/runtime 中的 helpers/classCallCheck。
安裝
npm i -D @babel/plugin-transform-runtime @babel/runtime
使用
在 .babelrc 檔案中
"plugins": [
        "@babel/plugin-transform-runtime"
]
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理 原文連結連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2846545/,如需轉載,請註明出處,否則將追究法律責任。

相關文章