关于性能优化:性能优化之windowonload

3次阅读

共计 4102 个字符,预计需要花费 11 分钟才能阅读完成。

前言

最近在做一些性能优化相干的工作,置信大家在工作过程中也会遇到一些性能优化相干的场景,这对于前端开发者来讲是一项加分技能。为了咱们的用户在应用咱们的产品时可能有一个十分好的体验,咱们须要对页面进行诊断优化。在行业中,咱们的页面 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 工作时,你会发现 DOMContentLoadedLoad事件都会等很久才会触发。

阐明 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 文档

如果这篇文章有帮忙到你,❤️关注 + 点赞❤️激励一下作者,关注 前端南玖 第一工夫获取最新文章~

正文完
 0