参考
https://segmentfault.com/a/1190000022205291
https://github.com/fouber/blog
https://segmentfault.com/a/1190000022696744
补充
字体图标代替图片图标
卡顿
动画或页面的帧率比设备屏幕刷新率(常见 60Hz)低时,会有卡顿的感觉
https://zhuanlan.zhihu.com/p/25166666
https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame
渲染流程
(js ->) style -> layout -> paint -> composite -> screen
Chrome devtool 中查看卡顿的帧
采集卡顿程度
https://fed.taobao.org/blog/taofed/do71ct/web-performance/?spm=taofed.blogs.blog-list.8.75e65ac8r0IX6q
1 2 3 4 5
| var t = new Date(); setInterval(function () { console.log(new Date() - t); t = new Date(); }, 100);
|
解决卡顿
- 对于 60Hz 来说,1 帧的时长约 (1000/60)ms,除去系统上下文切换开销,每一帧中只留给我们 10ms 左右的脚本处理时间
- js 脚本修改 DOM 造成 layout repaint,若脚本执行耗时长,这一帧耗时便长,屏幕刷新时这一帧还没更新就卡顿了,如何解决:
- 拆分该脚本,分在几帧里执行。帧耗时缩短,帧数变多,帧频提升
- 简化 DOM 结构
DOMContentLoaded 和 load 事件
DOMContentLoaded 事件 页面 DOM 加载完成即触发,而无需等待样式表、图像和子框架的完全加载
load 事件 全加载完毕
页面加载耗时
首屏耗时
在 window.onload 事件里执行 new Date() - performance.timing.navigationStart 即可获取首屏时间
适用于 SPA 的路由切换
Vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| function accAdd(arg1, arg2) { var r1, r2, m; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } m = Math.pow(10, Math.max(r1, r2)); return (arg1 * m + arg2 * m) / m; }
router.afterEach((to, from) => { let accumulatedRs = window.performance .getEntriesByType("resource") .map((item) => { let newItem = { name: item.name, duration: item.duration, }; return newItem; });
let storageRs = localStorage.accumulatedRs; let storageRsLength = 0; if (storageRs && storageRs.startsWith("[")) { if (JSON.parse(storageRs).length >= accumulatedRs.length) { storageRs = localStorage.accumulatedRs = ""; storageRsLength = 0; } else { storageRsLength = JSON.parse(storageRs).length; } } else { storageRs = localStorage.accumulatedRs = ""; storageRsLength = 0; }
let loadTime = 0; let len = accumulatedRs.length - storageRsLength; for (let i = 0; i < len; i++) { const r = accumulatedRs.slice(-len)[i]; loadTime = accAdd(loadTime, r.duration); } localStorage.accumulatedRs = JSON.stringify(accumulatedRs); let lastPage = router.resolve(from).href; console.log(`上个页面 = ${lastPage} --- 加载耗时 = ${loadTime.toFixed(2)}ms`); });
|
浏览器的渲染是单线程的
浏览器的渲染是单线程的,在某一个时刻要么在进行 JS 运算,要么在进行 UI 渲染。不会同时进行