We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近在專案上遇到小小的效能瓶頸
有一個畫面是顯示提貨點資訊的 list, 在初次渲染和使用filter時, 體感上會有明顯的 lag 原因是瀏覽器一次改變300多個dom節點造成的delay
來看看程式碼 這個 list 是由 state.currentRedemptionList 用 v-for 的方式渲染, 讓每一張 BsCard 呈現提貨點資料 而使用者可以藉由畫面上的 filter 對 state.currentRedemptionList 的數量進行增減
state.currentRedemptionList
在程式碼加上 timelog
onBeforeUpdate(() => { console.time('update list') }) onUpdated(() => { console.timeEnd('update list') })
可以看到使用 特快取件的 filter 反選時, 因為 list 數量一下從 8 => 346 re-render 過程大約需耗時高達 300ms
試試看用 Object.freeze 凍結傳進來的 list, 除去 vue observe data 的效能消耗
Object.freeze
<BsRedemptionPicker v-if="state.isShowRedemptionListPanel && stateSelectRedemption.sourceList" mode="declaration" :current-id="state.form.address" :redemption-list="Object.freeze(stateSelectRedemption.sourceList)" :express-name-key="address.addressFormat.expressNameKey" :redemption-shortcuts="address.addressFormat.consolidationRedemptionTypesGroupedShortcuts" @select="onSelectPanel" @goback="hideRedemptionListPanel" />
渲染耗時可以減少到大約 280ms, 效果不大
試試看將 state.currentRedemptionList 用 slice time 的方式重組 v-for 改成使用 stateTimeSlicing.list 去渲染 使用 setTimeout 在每次 eventLoop 時 分段將資料塞入列表
stateTimeSlicing.list
setTimeout
const stateTimeSlicing: any = reactive({ list: [], perPage: 20, timer: null, }) watch( () => state.currentRedemptionList, value => { timeSlice() }, { immediate: true }, ) function timeSlice() { stateTimeSlicing.list = [] clearTimeout(stateTimeSlicing.timer) stateTimeSlicing.timer = null loop(state.currentRedemptionList.length, 0) } function loop(curTotal: number, curIndex: number) { if (curTotal <= 0) { return false } const pageCount = Math.min(curTotal, stateTimeSlicing.perPage) stateTimeSlicing.timer = setTimeout(() => { stateTimeSlicing.list.push( ...state.currentRedemptionList.slice( curIndex, curIndex + pageCount, ), ) loop(curTotal - pageCount, curIndex + pageCount) }, 0) return true }
結果:在體感上已經感覺不到延遲了!
可以看到渲染時間被切成碎片化, 甚至第一次 component update 只需要3ms, 效果非常明顯
在優化後可以發現一個重點 雖然渲染速度變快了 但是卻造成畫面閃爍 原因是 在 timeSlice() 中的 stateTimeSlicing.list = [] 這段程式碼會造成 list 為空的狀態, 並且觸發 vue re-render
timeSlice()
stateTimeSlicing.list = []
我們稍微改一下程式碼就可以解決這個問題
function timeSlice() { clearTimeout(stateTimeSlicing.timer) stateTimeSlicing.timer = null loop(state.currentRedemptionList.length, 0) } function loop(curTotal: number, curIndex: number) { if (curTotal <= 0) { return false } const pageCount = Math.min(curTotal, stateTimeSlicing.perPage) stateTimeSlicing.timer = setTimeout(() => { if (curIndex === 0) stateTimeSlicing.list = [] stateTimeSlicing.list.push( ...state.currentRedemptionList.slice( curIndex, curIndex + pageCount, ), ) loop(curTotal - pageCount, curIndex + pageCount) }, 0) return true }
看看結果, 已經防止了畫面跳動的問題
以上 大功告成!
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
最近在專案上遇到小小的效能瓶頸
有一個畫面是顯示提貨點資訊的 list,
在初次渲染和使用filter時, 體感上會有明顯的 lag
原因是瀏覽器一次改變300多個dom節點造成的delay
來看看程式碼
這個 list 是由
state.currentRedemptionList
用 v-for 的方式渲染, 讓每一張 BsCard 呈現提貨點資料而使用者可以藉由畫面上的 filter 對
state.currentRedemptionList
的數量進行增減在程式碼加上 timelog
可以看到使用 特快取件的 filter 反選時,
因為 list 數量一下從 8 => 346
re-render 過程大約需耗時高達 300ms
第一步
試試看用
Object.freeze
凍結傳進來的 list, 除去 vue observe data 的效能消耗渲染耗時可以減少到大約 280ms, 效果不大
第二步
試試看將
state.currentRedemptionList
用 slice time 的方式重組v-for 改成使用
stateTimeSlicing.list
去渲染使用
setTimeout
在每次 eventLoop 時 分段將資料塞入列表結果:在體感上已經感覺不到延遲了!
可以看到渲染時間被切成碎片化, 甚至第一次 component update 只需要3ms, 效果非常明顯
第三步
在優化後可以發現一個重點
雖然渲染速度變快了
但是卻造成畫面閃爍
原因是 在
timeSlice()
中的stateTimeSlicing.list = []
這段程式碼會造成 list 為空的狀態, 並且觸發 vue re-render
我們稍微改一下程式碼就可以解決這個問題
看看結果, 已經防止了畫面跳動的問題
以上
大功告成!
參考資料
The text was updated successfully, but these errors were encountered: