性能优化之window.onload
前言
最近在做一些性能优化相关的工作,相信大家在工作过程中也会遇到一些性能优化相关的场景,这对于前端开发者来讲是一项加分技能。为了我们的用户在使用我们的产品时能够有一个非常好的体验,我们需要对页面进行诊断优化。在行业中,我们的页面P90在两秒内算是达标,超过这个时间那么你就可能会流失部分用户。
TIP:P90指的是页面性能数据从小到大排序,在90%位置的数据。
比如:P90为两秒,那它的意思就是90%的用户都能够在两秒内打开页面
对于性能优化内容可能比较多,我们这里就先着重了解window.onload相关内容。对于页面加载时长,我们就避免不了涉及window.onload。
性能分析
做性能优化肯定免不了需要对页面性能进行分析,我们一般会使用ChromeDevTool作为基础的性能分析工具,观察页面性能情况
Network:观察网络资源加载耗时及顺序
Performace:观察页面渲染表现及JS执行情况
Lighthouse:对网站进行整体评分,找出可优化项
今天我们先着重来看Network的相关内容,比如我们打开浏览器控制台:
这里我们可以看到这两项数据:DOMContentLoaded时间为841ms、Load时间为2.06s
它俩分别对应两个事件:
DOMContentLoaded
当初始的 HTML 文档被完全加载和解析完成之后,
DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完全加载。
Load
load事件在整个页面及所有依赖资源如样式表和图片都已完成加载时触发。它与DOMContentLoaded不同,后者只要页面 DOM 加载完成就触发,无需等待依赖资源的加载。
看完两者的解释之后,相信大家应该明白了为什么Load花的时间要比DOMContentLoaded长了吧
因为load事件会被大量媒体资源阻塞,浏览器只有在它认为页面上的所有资源都加载完成了才会触发load事件。
两者的区别
- DOM完整的解析过程:
- 解析HTML
- 加载外部脚本与样式文件
- 解析并执行脚本
- DOM树构建(DOMContentLoaded事件触发)
- 加载图片等资源
- 页面加载完毕(Load事件触发)
- DOM的解析受JS加载和执行的影响,我们在优化时应尽量对JS进行压缩、拆分处理(HTTP2下),能减少
DOMContentLoaded时间 - 图片、视频、CSS等资源,会阻塞 onload 事件的触发,我们在优化过程中需要优化资源的加载时机,让
load事件尽快触发
深入理解window.onload
onload触发时机
JS 加载并执行完毕且页面中所有外链资源加载完成之后大约 3 - 4ms(这个值跟机型和浏览器有关)
比如:
window.onload = () => {
console.log('load')
}
setTimeout(() => {
console.log('timeout')
}, 3)
结果是setTimeout先执行,这里把值改的稍大一点你会发现就是load先执行了
哪些因素会影响window.onload
JS执行
window.onload = () => {
console.log('load')
}
for(let i = 0; i < 100000; i++) {
console.log(i)
}
当我们写了一个非常耗时的JS任务时,你会发现DOMContentLoaded与Load事件都会等很久才会触发。
说明JS的执行不仅会阻塞DOMContentLoaded事件的触发,也会阻塞Load事件的触发。所以在优化过程中,JS也是一个重点关注对象。
async异步加载脚本
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.47/vue.cjs.js" async></script>
<script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/4.2.1/chart.js"></script>
为了对比,这里我加载了两个JS文件,一个使用async异步加载,一个直接加载,我们再到控制台来查看此时的加载情况。
这里我们可以看到两个文件都是在Load之前就会加载,只不过使用了async异步加载会比正常加载的后加载,说明使用了async异步加载脚本依然会阻塞Load的触发。
关于async的解释MDN上是这样说的:
对于普通脚本,如果存在
async属性,那么普通脚本会被并行请求,并尽快解析和执行。对于模块脚本,如果存在
async属性,那么脚本及其所有依赖都会在延缓队列中执行,因此它们会被并行请求,并尽快解析和执行。该属性能够消除解析阻塞的 Javascript。解析阻塞的 Javascript 会导致浏览器必须加载并且执行脚本,之后才能继续解析。
这里可能会有误解,我觉得它应该是不会阻塞其它脚本内容的加载与执行,由于它的加载是在load之前的,所以它依然会阻塞load的触发,但从整体上来看,它对性能优化还是有帮助的。
defer异步加载脚本
这里还是跟上面一样的场景,我们把async换成defer
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.47/vue.cjs.js" defer></script>
<script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/4.2.1/chart.js"></script>
这里看上去跟async的加载没什么不同,它的加载依然会比正常加载的方式滞后,但会在load之前。
关于defer:
这个布尔属性的设置是为了向浏览器表明,该脚本是要在文档被解析后,但在触发
DOMContentLoaded事件之前执行的。包含
defer属性的脚本将阻塞DOMContentLoaded事件触发,直到脚本完成加载并执行。包含
defer属性的脚本会按照它们出现在文档中的顺序执行。这个属性能够消除阻塞解析的 JavaScript,在这种情况下,浏览器必须在继续解析之前加载和执行脚本。
所以这里跟上面差不多,对性能优化也是有帮助的,需要注意使用场景。
图片预加载
在工作过程中我们可能会有一些图片预加载的使用场景,主要是为了能够让一些较大的图片资源能够快速的渲染呈现给用户,我们一般会提前加载一次图片,等到真正使用时浏览器就可以直接从缓存中取出并渲染。
<div class="container">
<img src="https://imgservices.image.com/s06012023/9ac85415.g0q5wz.png" class="zan_icon" />
</div>
<script>
window.onload = () => {
console.log('load')
}
const img = new Image();
img.src = 'https://router.vuejs.org/logo.svg';
</script>
比如这里,我们在html里面通过img加载了一张图片,在JS中预加载了一张图片,虽然这张图片并没有真实渲染,但它也是会发起请求的,并影响load事件的触发。
所以我们在做预加载时也需要考虑给页面性能带来的影响
影响load时间执行的内容还有很多,在对页面进行性能优化时,这些内容都是可以进行优化方向
onload与native
我们都知道H5页面在通过native得webview容器进行渲染时,顶部都会有一个加载进度条,有时候在弱网环境下,这个进度条会一直在那慢慢加载,很长时间不会消失,非常影响用户体验,这最主要的原因是onload 的触发被阻塞,从而客户端控制的进度条不会消失,页面调用客户端的方法不会执行。
iOS 中判断 webview 加载完成的 webViewDidFinishLoad 方法,Android 中判断 webview 加载完成的 onPageFinished 方法本质触发时机上都对应页面上的 window.onload,一般来说会稍晚于 window.onload(某些特殊情况会早于 window.onload,比如页面里有 iframe 等情况)。
也就是说 对 onload 有影响的因素也同样会影响这些 Native 方法。而在 Hybrid 开发中,一些 Native 和 Web 之间的交互和调用往往要在webViewDidFinishLoad / onPageFinished 之后。因此如果 onload 的触发被推迟了,那么这些 Native 相关的调用也都会被推迟。
因此如果是Hybrid应用,尤其要注意让onload尽快触发。
performance性能统计
DOMContentLoaded事件与Load事件花费的时间,我们可以通过performance 这个对象的一些属性进行统计,时间精确到纳秒级。很多公司的性能监控平台也主要是利用这个对象的数据进行上报的。
connectStart:HTTP(TCP)开始建立连接的时间。如果是持久连接,则和 fetchStart 的时间相等,注意,如果在传输层发生了错误且重新建立连接,这里显示的是新建立连接的开始时间。
connectEnd: 完成建立连接的时间。
domComplete:DOM 树解析完成,并且资源准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件。
domContentLoadedEventEnd:DOM 解析完成后,网页内资源加载完成的时间(如 JS、css 加载执行完毕)。
domContentLoadedEventStart:DOM 解析完成后,网页内资源加载开始的时间在 DOMContentLoaded 事件抛出前发生。
loadEventStart:load 事件触发,也即 load 回调函数开始执行的时间。注意:如果没有绑定 load 事件,值为 0。
loadEventEnd:load 事件的回调函数执行完毕的时间。
等...更详细内容可查看MDN文档
如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,关注 前端南玖 第一时间获取最新文章~
性能优化之window.onload的更多相关文章
- Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译
本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...
- Unity性能优化(1)-官方教程The Profiler window翻译
本文是Unity官方教程,性能优化系列的第一篇<The Profiler window>的简单翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻 ...
- H5 缓存机制浅析 移动端 Web 加载性能优化
腾讯Bugly特约作者:贺辉超 1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5 引入的离线存储, ...
- JavaScript 的性能优化:加载和执行
随着 Web2.0 技术的不断推广,越来越多的应用使用 javascript 技术在客户端进行处理,从而使 JavaScript 在浏览器中的性能成为开发者所面临的最重要的可用性问题.而这个问题又因 ...
- 关于DOM操作的性能优化
最著名的有关用js操作dom的观点是:js和dom是独立的小岛,用桥实现两者的联系,但桥很窄,要过路费,所以我们要尽最大可能减少过桥的次数.下面代码演示了用js操作dom的innerHTML,且一下修 ...
- [转]JavaScript 的性能优化:加载和执行
原文链接:http://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/index.html?ca=drs- JavaScript 的性能优化: ...
- Web性能优化工具WebPageTest(二)——性能数据
在前一篇<配置>完成后,点击“START TEST”,就可以开始测试,测试需要一段时间. 有时候可能还要排队,如下图所示,测试完成后可查看到测试结果. 一.Summary 1)优化等级 优 ...
- web前端性能优化总结
网站的划分一般为二:前端和后台.我们可以理解成后台是用来实现网站的功能的,比如:实现用户注册,用户能够为文章发表评论等等.而前端呢?其实应该是属于功能的表现.并且影响用户访问体验的绝大部分来自前端页面 ...
- Web前端性能优化——如何提高页面加载速度
前言: 在同样的网络环境下,两个同样能满足你的需求的网站,一个"Duang"的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网页时间是2-5秒, ...
- javascript的性能优化tips
谈到javascript的性能优化,有好多点,比如把script放到离body闭合标签附近,合并多个script标签等等,还有一些代码的性能,for的性能不如while的性能好,用while模拟for ...
随机推荐
- arc076f F - Exhausted?
ARC076 F - Exhausted? [题目大意] \(有m个座位,分别位于坐标为1,2,3,...,m的地方:n个客人,第i位客人只坐位于[0,li]∪[ri,m]的座位.每个座位只能坐一个人 ...
- 补五月四号java基础知识
1.在JDK5中新增了自动包装和自动解包功能:当编译器发现程序再应该使用包装类对象的地方却使用基本数据类型的数据时,编译器将自动把该数据包装为该基本数据对应的包装类的对象,这个过程成为自动包装.如类型 ...
- SpringBoot整合RocketMQ,老鸟们都是这么玩的!
今天我们来讨论如何在项目开发中优雅地使用RocketMQ.本文分为三部分,第一部分实现SpringBoot与RocketMQ的整合,第二部分解决在使用RocketMQ过程中可能遇到的一些问题并解决他们 ...
- DG修复:修改密码文件导致归档不应用
问题描述:重启完备库,之后发现主备同步状态异常,mrp进程状态显示applying log,但是v$datagaurd_stats视图中查询到归档日志并没有在应用.主库切换归档,可以正常传输过来,但是 ...
- hackathon 复盘:niche 海外软件工具正确的方法 6 个步骤
上周末,去参加了北京思否 hackathon,两天时间内从脑暴 & 挖掘软件 IDEA -> Demo 研发路演,这次经历让我难忘.这里我的看法是每个开发者圈友,都应该去参加一次 hac ...
- 【深入浅出Spring原理及实战】「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常
学习Spring源码的建议 阅读Spring官方文档,了解Spring框架的基本概念和使用方法. 下载Spring源码,可以从官网或者GitHub上获取. 阅读Spring源码的入口类,了解Sprin ...
- 从原理聊JVM(二):从串行收集器到分区收集开创者G1
作者:京东科技 康志兴 1 前言 随着Java的进化过程,涌现出各种不同的垃圾回收器,从串行执行到并行执行,从高吞吐到低延迟,终极目标就是让开发人员专注于程序的代码书写而无需关注内存管理. JDK早期 ...
- ES6 新增的一些特性
还有symbol和set,map, bind,call,apply 1. let关键字 (1)基本用法:let关键字用来声明变量,它的用法类似于var,都是用来声明变量. (2)块级作用域:let声明 ...
- C# 组合键判断
e.KeyboardDevice.Modifiers 同时按下了Ctrl + H键(H要最后按,因为判断了此次事件的e.Key)修饰键只能按下Ctrl,如果还同时按下了其他修饰键,则不会进入 1 pr ...
- [C++提高编程] 1、模板
文章目录 1 模板 1.1 模板的概念 1.2 函数模板 1.2.1 函数模板语法 1.2.2 函数模板注意事项 1.2.3 函数模板案例 1.2.4 普通函数与函数模板的区别 1.2.5 普通函数与 ...