
面試過程中面試官問到前端性能優(yōu)化有哪些,當我咔咔一頓輸出之后面試官追問:前端可以做的性能優(yōu)化有哪些呢?
前端優(yōu)化大概可以有以下幾個方向:
網(wǎng)絡優(yōu)化
頁面渲染優(yōu)化
JS優(yōu)化
圖片優(yōu)化
webpack打包優(yōu)化
React優(yōu)化
Vue優(yōu)化
網(wǎng)絡優(yōu)化
DNS預解析
link標簽的rel屬性設置dns-prefetch,提前獲取域名對應的IP地址
使用緩存
減輕服務端壓力,快速得到數(shù)據(jù)(強緩存和協(xié)商緩存可以看這里)
使用 CDN(內(nèi)容分發(fā)網(wǎng)絡)
用戶與服務器的物理距離對響應時間也有影響。
內(nèi)容分發(fā)網(wǎng)絡(CDN)是一組分散在不同地理位置的 web 服務器,用來給用戶更高效地發(fā)送內(nèi)容。典型地,選擇用來發(fā)送內(nèi)容的服務器是基于網(wǎng)絡距離的衡量標準的。例如:選跳數(shù)(hop)最少的或者響應時間最快的服務器。
壓縮響應
壓縮組件通過減少 HTTP 請求產(chǎn)生的響應包的大小,從而降低傳輸時間的方式來提高性能。從 HTTP1.1 開始,Web 客戶端可以通過 HTTP 請求中的 Accept-Encoding 頭來標識對壓縮的支持(這個請求頭會列出一系列的壓縮方法)
如果 Web 服務器看到請求中的這個頭,就會使用客戶端列出的方法中的一種來壓縮響應。Web 服務器通過響應中的 Content-Encoding 頭來告知 Web 客戶端使用哪種方法進行的壓縮
目前許多網(wǎng)站通常會壓縮 HTML 文檔,腳本和樣式表的壓縮也是值得的(包括 XML 和 JSON 在內(nèi)的任何文本響應理論上都值得被壓縮)。但是,圖片和 PDF 文件不應該被壓縮,因為它們本來已經(jīng)被壓縮了。
使用多個域名
Chrome 等現(xiàn)代化瀏覽器,都會有同域名限制并發(fā)下載數(shù)的情況,不同的瀏覽器及版本都不一樣,使用不同的域名可以最大化下載線程,但注意保持在 2~4 個域名內(nèi),以避免 DNS 查詢損耗。
避免圖片src為空
雖然 src 屬性為空字符串,但瀏覽器仍然會向服務器發(fā)起一個 HTTP 請求:
IE 向頁面所在的目錄發(fā)送請求; Safari、Chrome、Firefox 向頁面本身發(fā)送請求; Opera 不執(zhí)行任何操作。
頁面渲染優(yōu)化
Webkit 渲染引擎流程:
處理 HTML 并構建 DOM 樹
處理 CSS 構建 CSS 規(guī)則樹(CSSOM)
DOM Tree 和 CSSOM Tree 合成一棵渲染樹 Render Tree。
根據(jù)渲染樹來布局,計算每個節(jié)點的位置
調(diào)用 GPU 繪制,合成圖層,顯示在屏幕上
避免css阻塞
css影響renderTree的構建,會阻塞頁面的渲染,因此應該盡早(將 CSS 放在 head 標簽里)和盡快(啟用 CDN 實現(xiàn)靜態(tài)資源加載速度的優(yōu)化)的將css資源加載
降低css選擇器的復雜度
瀏覽器讀取選擇器,遵循的原則是從選擇器的右邊到左邊讀取。
減少嵌套:最多不要超過三層,并且后代選擇器的開銷較高,慎重使用
避免使用通配符,對用到的元素進行匹配即可
利用繼承,避免重復匹配和定義
正確使用類選擇器和id選擇器
避免使用CSS 表達式
css 表達式會被頻繁地計算。
避免js阻塞
js可以修改CSSOM和DOM,因此js會阻塞頁面的解析和渲染,并且會等待css資源的加載。也就是說js會搶走渲染引擎的控制權。所以我們需要給js資源添加defer或者async,延遲js腳本的執(zhí)行。
使用外鏈式的js和css
在現(xiàn)實環(huán)境中使用外部文件通常會產(chǎn)生較快的頁面,因為 JavaScript 和 CSS 有機會被瀏覽器緩存起來。對于內(nèi)聯(lián)的情況,由于 HTML 文檔通常不會被配置為可以進行緩存的,所以每次請求 HTML 文檔都要下載 JavaScript 和 CSS。所以,如果 JavaScript 和 CSS 在外部文件中,瀏覽器可以緩存它們,HTML 文檔的大小會被減少而不必增加 HTTP 請求數(shù)量。
使用字體圖標 iconfont 代替圖片圖標
圖片會增加網(wǎng)絡請求次數(shù),從而拖慢頁面加載時間
iconfont可以很好的縮放并且不會添加額外的請求
首屏加載優(yōu)化
使用骨架屏或者動畫優(yōu)化用戶體驗
資源按需加載,首頁不需要的資源延遲加載
減少重繪和回流
增加多個節(jié)點使用documentFragment:不是真實dom的部分,不會引起重繪和回流
用 translate 代替 top ,因為 top 會觸發(fā)回流,但是translate不會。所以translate會比top節(jié)省了一個layout的時間
使用 visibility 替換 display: none ,因為前者只會引起重繪,后者會引發(fā)回流(改變了布局);opacity 代替 visiability,visiability會觸發(fā)重繪(paint),但opacity不會。
把 DOM 離線后修改,比如:先把 DOM 給 display:none (有一次 Reflow),然后你修改 100 次,然后再把它顯示出來
不要把 DOM 結點的屬性值放在一個循環(huán)里當成循環(huán)里的變量
for (let i = 0; i < 1000; i++) {
// 獲取 offsetTop 會導致回流,因為需要去獲取正確的值console.log(document.querySelector('.test').style.offsetTop)
}
復制代碼
盡量少用table布局,table布局的話,每次有單元格布局改變,都會進行整個tabel回流重繪;
最好別頻繁去操作DOM節(jié)點,最好把需要操作的樣式,提前寫成class,之后需要修改。只需要修改一次,需要修改的時候,直接修改className,做成一次性更新多條css DOM屬性,一次回流重繪總比多次回流重繪要付出的成本低得多;
動畫實現(xiàn)的速度的選擇,動畫速度越快,回流次數(shù)越多,也可以選擇使用 requestAnimationFrame
每次訪問DOM的偏移量屬性的時候,例如獲取一個元素的scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft、offsetWidth、offsetHeight之類的屬性,瀏覽器為了保證值的正確也會回流取得最新的值,所以如果你要多次操作,最取完做個緩存。更加不要for循環(huán)中訪問DOM偏移量屬性,而且使用的時候,最好定義一個變量,把要需要的值賦值進去,進行值緩存,把回流重繪的次數(shù)減少;
將頻繁運行的動畫變?yōu)閳D層,圖層能夠阻止該節(jié)點回流影響別的元素。比如對于 video 標簽,瀏覽器會自動將該節(jié)點變?yōu)閳D層。
JS中的性能優(yōu)化
使用事件委托
防抖和節(jié)流
盡量不要使用JS動畫
css3動畫和canvas動畫都比JS動畫性能好
多線程
復雜的計算開啟webWorker進行計算,避免頁面假死
計算結果緩存
減少運算次數(shù),比如vue中的computed
圖片的優(yōu)化
雪碧圖
借助減少http請求次數(shù)來進行優(yōu)化
圖片懶加載
在圖片即將進入可視區(qū)域的時候進行加載(判斷圖片進入可視區(qū)域請參考這里)
使用CSS3代替圖片
有很多圖片使用 CSS 效果(漸變、陰影等)就能畫出來,這種情況選擇 CSS3 效果更好
圖片壓縮
壓縮方法有兩種,一是通過在線網(wǎng)站進行壓縮,二是通過 webpack 插件 image-webpack-loader。它是基于 imagemin 這個 Node 庫來實現(xiàn)圖片壓縮的。
使用 webp 格式的圖片
webp 是一種新的圖片文件格式,它提供了有損壓縮和無損壓縮兩種方式。在相同圖片質(zhì)量下,webp 的體積比 png 和 jpg 更小。
webpack打包優(yōu)化
縮小loader 匹配范圍
優(yōu)化loader配置
test、include、exclude三個配置項來縮?loader的處理范圍
推薦include
include: path.resolve(__dirname, "./src"),
復制代碼
resolve.modules
resolve.modules用于配置webpack去哪些目錄下尋找第三方模塊,默認是 node_modules。
尋找第三方,默認是在當前項目目錄下的node_modules里面去找,如果沒有找到,就會去上一級目錄../node_modules找,再沒有會去../../node_modules中找,以此類推,和Node.js的模塊尋找機制很類似。
如果我們的第三?模塊都安裝在了項?根?錄下,就可以直接指明這個路徑。
module.exports={
resolve:{
modules: [path.resolve(__dirname, "./node_modules")]
}
}
resolve.extensions
resolve.extensions在導?語句沒帶?件后綴時,webpack會?動帶上后綴后,去嘗試查找?件是否存在。
后綴嘗試列表盡量的?
導?語句盡量的帶上后綴。
如果想優(yōu)化到極致的話,不建議用extensionx, 因為它會消耗一些性能。雖然它可以帶來一些便利。
抽離css
借助mini-css-extract-plugin:本插件會將 CSS 提取到單獨的文件中,為每個包含 CSS 的 JS 文件創(chuàng)建一個 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加載。。
constMiniCssExtractPlugin = require("mini-css-extract-plugin");
{
test: /\.less$/,
use: [
// "style-loader", // 不再需要style-loader,?MiniCssExtractPlugin.loader代替MiniCssExtractPlugin.loader,
"css-loader", // 編譯css"postcss-loader",
"less-loader"http:// 編譯less
]
},
plugins: [
newMiniCssExtractPlugin({
filename: "css/[name]_[contenthash:6].css",
chunkFilename: "[id].css"
})
]
復制代碼
代碼壓縮
JS代碼壓縮
mode:production,使用的是terser-webpack-plugin
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [
newTerserPlugin({}),
]
}
}
復制代碼
CSS代碼壓縮
css-minimizer-webpack-plugin
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [
newCssMinimizerPlugin({})
]
}
}
復制代碼
Html文件代碼壓縮
module.exports = {
...
plugin:[
newHtmlwebpackPlugin({
...
minify:{
minifyCSS:false, // 是否壓縮css
collapseWhitespace:false, // 是否折疊空格
removeComments:true// 是否移除注釋
}
})
]
}
復制代碼
設置了minify,實際會使用另一個插件html-minifier-terser
文件大小壓縮
對文件的大小進行壓縮,減少http傳輸過程中寬帶的損耗
npm install compression-webpack-plugin -D
復制代碼
newComepressionPlugin({
test:/.(css|js)$/, // 哪些文件需要壓縮
threshold:500, // 設置文件多大開始壓縮
minRatio:0.7, // 至少壓縮的比例
algorithm:"gzip", // 采用的壓縮算法
})
復制代碼
圖片壓縮
一般來說在打包之后,一些圖片文件的大小是遠遠要比 js 或者 css 文件要來的大,所以圖片壓縮較為重要
配置方法如下:
module: {
rules: [
{
test:/.(png|jpg|gif)$/,
use: [
{
loader:'file-loader',
options: {
name:'[name]_[hash].[ext]',
outputPath:'images/',
}
},
{
loader:'image-webpack-loader',
options: {
//壓縮jpeg的配置
mozjpeg: {
progressive:true,
quality:65
},
//使用imagemin**-optipng壓縮png,enable:false為關閉
optipng: {
enabled:false,
},
//使用imagemin-pngquant壓縮png
pngquant: {
quality:'65-90',
speed:4
},
//壓縮gif的配置
gifsicle: {
interlaced:false,
},
//開啟webp,會把jpg和png圖片壓縮為webp格式
webp: {
quality:75
}
}
}
]
},
]
}
復制代碼
Tree shaking 去除死代碼
Tree Shaking 是一個術語,在計算機中表示消除死代碼,依賴于ES Module的靜態(tài)語法分析(不執(zhí)行任何的代碼,可以明確知道模塊的依賴關系)
在webpack實現(xiàn)Tree shaking有兩種不同的方案:
usedExports:通過標記某些函數(shù)是否被使用,之后通過Terser來進行優(yōu)化的
sideEffects:跳過整個模塊/文件,直接查看該文件是否有副作用
兩種不同的配置方案, 有不同的效果
usedExports
配置方法也很簡單,只需要將usedExports設為true
module.exports = {
...
optimization:{
usedExports
}
}
復制代碼
使用之后,沒被用上的代碼在webpack打包中會加入unused harmony export mul注釋,用來告知 Terser 在優(yōu)化時,可以刪除掉這段代碼
sideEffects
sideEffects用于告知webpack compiler哪些模塊時有副作用,配置方法是在package.json中設置sideEffects屬性
如果sideEffects設置為false,就是告知webpack可以安全的刪除未用到的exports
如果有些文件需要保留,可以設置為數(shù)組的形式
"sideEffecis":[
"./src/util/format.js",
"*.css"http:// 所有的css文件]復制代碼
上述都是關于javascript的tree shaking,css同樣也能夠實現(xiàn)tree shaking
css tree shaking
css進行tree shaking優(yōu)化可以安裝PurgeCss插件
npm install purgecss-plugin-webpack -D
constPurgeCssPlugin = require('purgecss-webpack-plugin')
module.exports = {
...
plugins:[
newPurgeCssPlugin({
path:glob.sync(`${path.resolve('./src')}/**/*`), {nodir:true}// src里面的所有文件
satelist:function(){
return {
standard:["html"]
}
}
})
]
}
復制代碼
paths:表示要檢測哪些目錄下的內(nèi)容需要被分析,配合使用glob
默認情況下,Purgecss會將我們的html標簽的樣式移除掉,如果我們希望保留,可以添加一個safelist的屬性
babel-plugin-transform-runtime減少ES6轉化ES5的冗余
Babel 插件會在將 ES6 代碼轉換成 ES5 代碼時會注入一些輔助函數(shù)。在默認情況下, Babel 會在每個輸出文件中內(nèi)嵌這些依賴的輔助函數(shù)代碼,如果多個源代碼文件都依賴這些輔助函數(shù),那么這些輔助函數(shù)的代碼將會出現(xiàn)很多次,造成代碼冗余。為了不讓這些輔助函數(shù)的代碼重復出現(xiàn),可以在依賴它們時通過 require('babel-runtime/helpers/createClass') 的方式導入,這樣就能做到只讓它們出現(xiàn)一次。babel-plugin-transform-runtime 插件就是用來實現(xiàn)這個作用的,將相關輔助函數(shù)進行替換成導入語句,從而減小 babel 編譯出來的代碼的文件大小。
代碼分離
將代碼分離到不同的bundle中,之后我們可以按需加載,或者并行加載這些文件
默認情況下,所有的JavaScript代碼(業(yè)務代碼、第三方依賴、暫時沒有用到的模塊)在首頁全部都加載,就會影響首頁的加載速度
代碼分離可以分出更小的bundle,以及控制資源加載優(yōu)先級,提供代碼的加載性能
這里通過splitChunksPlugin來實現(xiàn),該插件webpack已經(jīng)默認安裝和集成,只需要配置即可
默認配置中,chunks僅僅針對于異步(async)請求,我們可以設置為initial或者all
module.exports = {
...
optimization:{
splitChunks:{
chunks:"all"
}
}
}
復制代碼
splitChunks主要屬性有如下:
Chunks,對同步代碼還是異步代碼進行處理
minSize: 拆分包的大小, 至少為minSize,如何包的大小不超過minSize,這個包不會拆分
maxSize: 將大于maxSize的包,拆分為不小于minSize的包
minChunks:被引入的次數(shù),默認是1
多線程打包提升打包速度
vue
v-for添加key
路由懶加載
第三方插件按需引入
合理使用computed和watch
v-for的同時避免使用v-if
destory時銷毀事件:比如addEventListener添加的事件、setTimeout、setInterval、bus.$on綁定的監(jiān)聽事件等
react
map循環(huán)展示添加key
路由懶加載
第三方插件按需引入
使用scu,memo或者pureComponent避免不必要的渲染
合理使用useMemo、memo、useCallback
他們?nèi)齻€的應用場景都是緩存結果,當依賴值沒有改變時避免不必要的計算或者渲染。
useCallback 是針對函數(shù)進行“記憶”的,當它依賴項沒有發(fā)生改變時,那么該函數(shù)的引用并不會隨著組件的刷新而被重新賦值。當我們覺得一個函數(shù)不需要隨著組件的更新而更新引用地址的時候,我們就可以使用 useCallback 去修飾它。
React.memo 是對組件進行 “記憶”,當它接收的 props 沒有發(fā)生改變的時候,那么它將返回上次渲染的結果,不會重新執(zhí)行函數(shù)返回新的渲染結果。文章來源:http://www.zghlxwxcb.cn/news/detail-412829.html
React.useMemo是針對 值計算 的一種“記憶“,當依賴項沒有發(fā)生改變時,那么無需再去計算,直接使用之前的值,對于組件而言,這帶來的一個好處就是,可以減少一些計算,避免一些多余的渲染。當我們遇到一些數(shù)據(jù)需要在組件內(nèi)部進行計算的時候,可以考慮一下 React.useMemo文章來源地址http://www.zghlxwxcb.cn/news/detail-412829.html
到了這里,關于【面試題】2023當面試官問我前端可以做的性能優(yōu)化有哪些的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!