JavaScript針對(duì)SPA應(yīng)用的前端優(yōu)化策略概述
性能優(yōu)化
所有開發(fā)者都無法避免的一個(gè)問題,即關(guān)于項(xiàng)目的性能優(yōu)化。性能優(yōu)化是一個(gè)經(jīng)久不衰的問題,它幾乎貫穿于整個(gè)項(xiàng)目的開發(fā)過程。做好性能優(yōu)化的項(xiàng)目不僅能在用戶體驗(yàn)上更勝一籌,還能讓服務(wù)資源的分配更加的合理。
關(guān)于SPA單頁面應(yīng)用程序的優(yōu)化
前端開發(fā)者基本上都知道單頁面的程序有一個(gè)通病,首屏加載太慢了,因?yàn)榈谝淮卧L問的時(shí)候需要加載的東西太多,資源量太大以至于體驗(yàn)起來可能并不那么友好,以下就這個(gè)點(diǎn)便可以針對(duì)性地展開優(yōu)化。
1、路由懶加載
SPA 項(xiàng)目,一個(gè)路由對(duì)應(yīng)一個(gè)頁面,如果不做處理,項(xiàng)目打包后,會(huì)把所有頁面打包成一個(gè)文件,當(dāng)用戶打開首頁時(shí),會(huì)一次性加載所有的資源,造成首頁加載很慢,降低用戶體驗(yàn)。
官方其實(shí)也就這個(gè)問題給出了答復(fù),我們只需要按照他們的提示去改動(dòng)代碼,那么就可以在一定程度上去提高項(xiàng)目的運(yùn)行速度。
// 通過webpackChunkName設(shè)置分割后代碼塊的名字 const Home = () => import(/* webpackChunkName: "home" */ "@/views/home/index.vue"); const MetricGroup = () => import(/* webpackChunkName: "metricGroup" */ "@/views/metricGroup/index.vue"); ………… const routes = [ { path: "/", name: "home", component: Home }, { path: "/metricGroup", name: "metricGroup", component: MetricGroup }, ………… ]
2、組件懶加載
組件懶加載跟路由懶加載的方式一樣,將資源分開,等到需要的時(shí)候我們?cè)侔阉氲轿覀兊捻撁嬷校瑥亩?jié)省資源,優(yōu)化頁面的加載速度。
例如彈窗組件的懶加載。
<script> const dialogInfo = () => import(/* webpackChunkName: "dialogInfo" */ '@/components/dialogInfo'); export default { name: 'homeView', components: { dialogInfo } } </script>
重新打包后,home.js 和 about.js 中沒有了彈框組件的代碼,該組件被獨(dú)立打包成 dialogInfo.js,當(dāng)用戶點(diǎn)擊按鈕時(shí),才會(huì)去加載 dialogInfo.js 和 dialogInfo.css
組件懶加載的使用場(chǎng)景
有時(shí)資源拆分的過細(xì)也不好,可能會(huì)造成瀏覽器 http 請(qǐng)求的增多
總結(jié)出三種適合組件懶加載的場(chǎng)景:
1)該頁面的 JS 文件體積大,導(dǎo)致頁面打開慢,可以通過組件懶加載進(jìn)行資源拆分,利用瀏覽器并行下載資源,提升下載速度(比如首頁)
2)該組件不是一進(jìn)入頁面就展示,需要一定條件下才觸發(fā)(比如彈框組件)
3)該組件復(fù)用性高,很多頁面都有引入,利用組件懶加載抽離出該組件,一方面可以很好利用緩存,同時(shí)也可以減少頁面的 JS 文件大?。ū热绫砀窠M件、圖形組件等)
懶加載原理
懶加載前提的實(shí)現(xiàn):ES6的動(dòng)態(tài)地加載模塊——import()。
要實(shí)現(xiàn)懶加載,就得先將進(jìn)行懶加載的子模塊分離出來,打包成一個(gè)單獨(dú)的文件
webpackChunkName 作用是 webpack 在打包的時(shí)候,對(duì)異步引入的庫代碼(lodash)進(jìn)行代碼分割時(shí),設(shè)置代碼塊的名字。webpack 會(huì)將任何一個(gè)異步模塊與相同的塊名稱組合到相同的異步塊中
簡而言之,就是用懶加載后程序只會(huì)去加載你當(dāng)前頁面所需要的資源,不需要的資源暫時(shí)不會(huì)請(qǐng)求,而且在后續(xù)如果重復(fù)的資源被利用了,也不會(huì)再做請(qǐng)求,從而消耗了我們?yōu)g覽器資源。
3、Tree shaking的優(yōu)化
tree-shaking 原理:
依賴于ES6的模塊特性,ES6模塊依賴關(guān)系是確定的,和運(yùn)行時(shí)的狀態(tài)無關(guān),可以進(jìn)行可靠的靜態(tài)分析,這就是 tree-shaking 的基礎(chǔ)
靜態(tài)分析就是不需要執(zhí)行代碼,就可以從字面量上對(duì)代碼進(jìn)行分析。ES6之前的模塊化,比如 CommonJS 是動(dòng)態(tài)加載,只有執(zhí)行后才知道引用的什么模塊,就不能通過靜態(tài)分析去做優(yōu)化,正是基于這個(gè)基礎(chǔ)上,才使得 tree-shaking 成為可能
Tree shaking 的作用:
消除無用的 JS 代碼,減少代碼體積
對(duì)比以下兩端代碼
// 第一段 export function targetType(target) { return Object.prototype.toString.call(target).slice(8, -1).toLowerCase(); } export function deepClone(target) { return JSON.parse(JSON.stringify(target)); } // 第二段 export default { targetType(target) { return Object.prototype.toString.call(target).slice(8, -1).toLowerCase(); }, deepClone(target) { return JSON.parse(JSON.stringify(target)); } }; // 引入并使用 import util from '../util'; util.targetType(null)
其實(shí)兩者在使用上并無太大的區(qū)別,只是第二段又多做了一層封裝,但是這樣的封裝會(huì)讓tree shaking失效,使項(xiàng)目打包體積增大,降低我們資源包的精準(zhǔn)分配。因?yàn)槲覀兯M(jìn)行的封裝會(huì)默認(rèn)地把該文件中所有的函數(shù)整個(gè)被引入到組件頁面中,導(dǎo)致一些無用代碼的產(chǎn)生。
究其原因,export default 導(dǎo)出的是一個(gè)對(duì)象,無法通過靜態(tài)分析判斷出一個(gè)對(duì)象的哪些變量未被使用,所以 tree-shaking 只對(duì)使用 export 導(dǎo)出的變量生效
這也是函數(shù)式編程越來越火的原因,因?yàn)榭梢院芎美?tree-shaking 精簡項(xiàng)目的體積,也是 vue3 全面擁抱了函數(shù)式編程的原因之一
4、骨架屏優(yōu)化白屏?xí)r長
使用骨架屏,可以縮短白屏?xí)r間,提升用戶體驗(yàn)。國內(nèi)大多數(shù)的主流網(wǎng)站都使用了骨架屏,特別是手機(jī)端的項(xiàng)目
SPA 單頁應(yīng)用,無論 vue 還是 react,最初的 html 都是空白的,需要通過加載 JS 將內(nèi)容掛載到根節(jié)點(diǎn)上,這套機(jī)制的副作用:會(huì)造成長時(shí)間的白屏
常見的骨架屏插件就是基于這種原理,在項(xiàng)目打包時(shí)將骨架屏的內(nèi)容直接放到 html 文件的根節(jié)點(diǎn)中
使用骨架屏插件,打包后的 html 文件(根節(jié)點(diǎn)內(nèi)部為骨架屏):
骨架屏插件
①安裝插件
npm i vue-skeleton-webpack-plugin
②vue.config.js 配置
const SkeletonWebpackPlugin = require("vue-skeleton-webpack-plugin"); module.exports = { configureWebpack: { plugins: [ new SkeletonWebpackPlugin({ // 實(shí)例化插件對(duì)象 webpackConfig: { entry: { app: path.join(__dirname, './src/skeleton.js') // 引入骨架屏入口文件 } }, minimize: true, // SPA 下是否需要壓縮注入 HTML 的 JS 代碼 quiet: true, // 在服務(wù)端渲染時(shí)是否需要輸出信息到控制臺(tái) router: { mode: 'hash', // 路由模式 routes: [ // 不同頁面可以配置不同骨架屏 // 對(duì)應(yīng)路徑所需要的骨架屏組件id,id的定義在入口文件內(nèi) { path: /^\/home(?:\/)?/i, skeletonId: 'homeSkeleton' }, { path: /^\/detail(?:\/)?/i, skeletonId: 'detailSkeleton' } ] } }) ] } }
③新建 skeleton.js 入口文件
// skeleton.js import Vue from "vue"; // 引入對(duì)應(yīng)的骨架屏頁面 import homeSkeleton from "./views/homeSkeleton"; import detailSkeleton from "./views/detailSkeleton"; export default new Vue({ components: { homeSkeleton, detailSkeleton, }, template: ` <div> <homeSkeleton id="homeSkeleton" style="display:none;" /> <detailSkeleton id="detailSkeleton" style="display:none;" /> </div> `, });
以上這些就是SPA項(xiàng)目的優(yōu)化手段,像其他優(yōu)化的方式還有很多,但是我們應(yīng)該在項(xiàng)目的開發(fā)階段就考慮這樣的方案,不然會(huì)導(dǎo)致后續(xù)維護(hù)和優(yōu)化的成本變高。所以如有必要,我們應(yīng)該盡量在早期的時(shí)候就開始干涉項(xiàng)目的優(yōu)化進(jìn)度和性能水平,這樣才能持續(xù)輸出有質(zhì)量和易維護(hù)的產(chǎn)品。
到此這篇關(guān)于JavaScript針對(duì)SPA應(yīng)用的前端優(yōu)化策略概述的文章就介紹到這了,更多相關(guān)JS SPA前端優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript實(shí)現(xiàn)京東快遞單號(hào)的查詢效果
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)京東快遞單號(hào)的查詢效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11javascript數(shù)據(jù)結(jié)構(gòu)之串的概念與用法分析
這篇文章主要介紹了javascript數(shù)據(jù)結(jié)構(gòu)之串的概念與用法,簡單講述了串的概念、功能并結(jié)合實(shí)例形式分析了基于javascript實(shí)現(xiàn)串的遍歷、比較、查找等相關(guān)操作技巧,需要的朋友可以參考下2017-04-04Javascript中的方法鏈(Method Chaining)介紹
這篇文章主要介紹了Javascript中的方法鏈(Method Chaining)介紹,本文講解了Javascript Method Chaining、Method Chaining 使用、Method Chaining VS prototype Chaining等內(nèi)容,需要的朋友可以參考下2015-03-03js判斷兩個(gè)數(shù)組是否存在相同元素的四種方法
這篇文章主要給大家介紹了關(guān)于js判斷兩個(gè)數(shù)組是否存在相同元素的四種方法,js中是不能直接用==或者===來計(jì)算兩個(gè)數(shù)組是否相等的,那么就需要對(duì)數(shù)組的值進(jìn)行比較,需要的朋友可以參考下2023-07-07