前端优化系列 - 初始化的性能影响

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 数据表明,即使在资源有缓存的情况下,首次访问页面的耗时也是非首次访问的两倍。为什么首次访问会这么耗时呢?本文详细分析页面首次访问耗时的原因。

前言

数据表明,即使在资源有缓存的情况下,首次访问页面的耗时也是非首次访问的两倍。为什么首次访问会这么耗时呢?本文详细分析页面首次访问耗时的原因。

常见的初始化

我们先看看打开一个页面,需要经过那些流程。可能会包括,库加载(Load so,jar文件),外壳初始化,内核初始化,创建WebView,创建Renderer进程,初始化V8 JS引擎,初始化IPC,初始化CC,初始化网络库,初始化文件系统,初始化数据库,启动ServiceWorker线程(PWA页面),DNS解析,创建网络连接,页面服务器初始化,等等。这些流程前端一般是看不见的。

在讨论具体的耗时之前,我们先约定,下文所有的数据都是基于Nexus 5手机。不同的手机的性能数据差异极大,一些高端手机(比如,iPhone X),性能可能是中低端机的好几倍。

库加载

启动应用程序,需要先把一些库文件加载进内存,这个过程是特别耗时的,一般浏览器内核库有30M,大概需要300ms。如果是全新安装首次启动,还涉及到解压so和使用DexClassLoader去load dex,这些极其耗时,甚至会超过5秒。如果是使用multidex方案,在4.x及以下系统,会进一步增加启动耗时。

外壳初始化

浏览器外壳的初始化,用户点击桌面图标启动浏览器,浏览器会进入一个状态机,按步骤初始化各个功能模块,很多模块的初始化会涉及网络,文件IO,JNI,等等操作,这些都会有一定的耗时。

我们为什么需要关心浏览器启动的耗时呢?一些场景下,用户通过扫码或者点击桌面图标去访问页面,这个过程就会包含浏览器的启动流程,我们有必要了解这其中发生了什么。对于内置浏览器内核的App,比如,支付宝,手淘,情况又是怎样的呢?我们这边暂时没有支付宝和手淘的启动性能数据,但模块初始化,加载SO和JAR,这些流程都会有,时间不会很小。

在外壳初始化耗时方面,有没有一些比较好的解决办法呢?最好的办法就是进程保活,现在国内很多手机厂商都会给微信,支付宝,等超级App的进程保活,用户在任务列表杀掉了应用,其实进程还在。如果是多进程的情况,可以提前创建进程,比如,微信和支付宝的小程序,用户访问时可以直接使用预创建的进程。

内核初始化

浏览器内核的初始化,与外壳的初始化类似,内核的初始化也需要加载SO和JAR,创建WebView和初始化各个功能模块。

在创建WebView方面,全新安装首次创建约1秒,非全新安装首次创建约300ms,第二次创建约15ms。首次创建Renderrer进程,初始化IPC,初始化CC,这些耗时在百毫秒的级别;V8 引擎相关的初始化耗时也在百毫秒的级别,其中首次NewContext要20ms。

总的来说,首次访问加载SO和JAR一般需要500ms,创建WebView和走完内核流程一般需要消耗500ms,也就是说,应用程序如果提前初始化内核,预创建WebView和加载一个空白内容页面,跑一趟内核流程,可以为用户首次访问页面带来1秒的收益。

业务初始化

在页面加载的过程中,内核会有很多回调通知外壳,这些回调的处理上是否可能存在性能问题呢?

我们发现,在一些App上,一些接口很可能会出现性能问题,比如,onPageStarted,shouldOverrideUrlLoading,shouldInterceptRequest。

这些接口为什么会出现性能问题呢?一般很多应用会在首次onPageStarted回调时执行复杂的业务逻辑,比如,初始化一些统计模块,进行JS注入,等等。需要说明的是,onPageStarted并不是同步接口,为什么也会有影响呢?因为它是在UI线程执行的,长期占用UI线程,会对内核有较大的影响,内核很多操作需要抛转到UI线程去处理,比如,ServiceWorker线程启动就有抛转UI的过程,在UI执行完之前,它只能等待。

shouldOverrideUrlLoading 是客户端拦截请求的关键接口,内核会同步等待,很多应用会有比较复杂的拦截规则,往往比较耗时。

shouldInterceptRequest 是客户端离线包的关键接口,内核会同步等待,很多应用会在这个接口首次回调时去解压离线包和初始化离线模块。

在一些实际应用中,优化这些回调的处理,可以给全部H5页面带来 10% 以上的性能提升。

ServiceWorker初始化

ServiceWorker是PWA的关键技术,它具有非常强大的能力,Fetch,Cache,Push和Add to home screen,能让前端开发者非常灵活的操控页面缓存。

同时,它也是有比较大的初始化成本的,比如,ServiceWorker线程启动平均要200ms,而每次访问页面,一般ServiceWorker线程至少都需要启动一次。当然,Chrome也在不断优化这块的耗时,最终预计能优化到100ms以内。

关于ServiceWorker启动的性能,请参考:PWA系列 - Service Workers 启动性能

网络初始化

在网络初始化方面,一般内核网络库的初始化并不太耗时,耗时的是DNS和Connection。

用户首次访问,一般都需要去进行DNS解析和创建连接,而在后续访问时,一般都可以用上缓存或者预连接。

DNS解析,一般耗时在200ms以上,创建HTTP连接,一般耗时也在200ms以上,而创建HTTPS连接则需要600ms以上。

也就是说,用户首次访问时,如果不能提前创建连接,从性能的角度来说,是非常影响的。这个方面我们的建议是,使用HTTPDNS提前解析和缓存DNS,提前创建连接(比如,用户点击时)。浏览器也有这方面的优化,比如,在加载主文档时,提前发起子资源的预连接。

服务器初始化

页面服务器和资源服务器,是否也需要初始化呢?一般也是需要的,比如,页面访问过之后,页面服务器也会有一些缓存,用户再次访问时可以直接使用缓存而无需走完整的流程,但这些缓存应该是大部分用户都能共享的,所以实际影响不好评估。资源服务器也一样,比如,图床,很多是按用户手机屏幕和网络类型来返回不同图片的,用户访问过就会放到CDN缓存中。

暂时未有数据表明服务器初始化对页面整体性能产生明显影响。但我们有另外一份数据,在一个业务中,预创建WebView提前加载一次模版页面,能让全网平均性能优化100ms。其中,模版页是304的,里面的资源都是可缓存的,也就是说,这100ms的收益并不来于缓存,而是来于某些模块的初始化。

JS初始化

这里提到的JS初始化,并不是前面说的JS引擎相关的初始化。JS初始化是指JS文件缓存到httpcache和解析编译生成V8 Cache文件。很多数据表明,JS解析编译占JS耗时的35%以上,一些有巨型JS的页面甚至可以达到80%。在U4 2.0内核中,一般JS执行一次之后,就可以生成V8 Cache,虽然V8 Cache可以重复使用,但也存在被自动清理的情况,所以提前执行一次还是有收益的。

一些业务中,提前执行一次JS,在用户真实访问时,耗时从500ms降到200ms。特别是在一些超级App中,基础JS基本都一样,提前执行一次可能会带来非常明显的收益。

结束语

上面介绍了一些常见的初始化对页面性能的影响,希望大家能了解到一些隐藏的信息,能开阔Web优化的思路。当然,这些点不一定都会存在很大的性能问题,比如,一些业务模块处理的非常好的App,在业务初始化方面不一定会有性能问题,需要根据自己的实际场景,具体问题具体分析。

目录
相关文章
|
6月前
|
机器学习/深度学习 前端开发 算法
利用深度学习技术提升前端图像处理性能
本文将探讨如何利用深度学习技术在前端图像处理中提升性能。通过结合深度学习算法和前端技术,我们可以实现更高效的图像处理功能,提升用户体验和系统性能。
|
6月前
|
前端开发 数据可视化 JavaScript
前端vite+vue3——可视化页面性能耗时指标(fmp、fp)
前端vite+vue3——可视化页面性能耗时指标(fmp、fp)
262 6
|
6月前
|
缓存 前端开发 JavaScript
前端性能优化:高在性能,大在范围,必要前置知识一网打尽!(下)
在上一篇 前端性能优化:高在性能,大在范围,必要前置知识一网打尽!(上) 一文中介绍了和前端性能优化相关的一些前置知识,那么本篇就针对优化方案进行总结,核心的方向还是上篇文章中提到的内容:
|
6月前
|
缓存 前端开发 JavaScript
如何优化前端页面性能
前端性能优化是网站开发中非常重要的一部分,它直接关系到用户体验和网站的流量以及排名。本文将介绍一些优化前端页面性能的方法,包括减少HTTP请求、压缩代码、使用CDN等。
|
6月前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
266 0
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
3月前
|
缓存 前端开发 JavaScript
超时空加速秘籍:揭秘JavaScript前端开发中的性能魔法,让您的Web应用瞬间穿越到未来!
【8月更文挑战第27天】本文介绍了一系列实用的JavaScript性能优化方法并提供了示例代码,包括减少DOM操作、使用事件委托、避免阻塞主线程、异步加载资源、利用浏览器缓存、代码分割以及使用Service Worker等技术,帮助开发者有效提升Web应用性能和用户体验。
49 2
|
3月前
|
缓存 编解码 前端开发
优化Web应用性能的前端技巧:从加载时间到用户体验
在现代Web开发中,提升前端性能不仅仅是为了缩短页面加载时间,更是为了提供更流畅的用户体验。本文将探讨几种有效的前端优化技术,包括懒加载、代码拆分、资源压缩以及浏览器缓存策略。通过具体实例和最佳实践,读者将能够掌握如何系统地提高Web应用的响应速度,减少资源消耗,并最终改善用户的整体体验。
|
3月前
|
前端开发 JavaScript API
一场前端框架的“武林大会”,三大主流框架之间的性能比较!!!
一场前端框架的“武林大会”,三大主流框架之间的性能比较!!!
|
3月前
|
前端开发 UED 开发者
React组件优化全攻略:深度解析让你的前端应用飞速运行的秘诀——从PureComponent到React.memo的彻底性能比较
【8月更文挑战第31天】在构建现代Web应用时,性能是提升用户体验的关键因素。React作为主流前端库,其组件优化尤为重要。本文深入探讨了React组件优化策略,包括使用`PureComponent`、`React.memo`及避免不必要的渲染等方法,帮助开发者显著提升应用性能。通过实践案例对比优化前后效果,不仅提高了页面渲染速度,还增强了用户体验。优化React组件是每个开发者必须关注的重点。
63 0
|
3月前
|
前端开发 JavaScript 开发者
掌握Web前端事件处理精髓:从事件冒泡到事件委托,轻松优化你的交互体验与代码性能!
【8月更文挑战第23天】在Web前端开发中,事件处理是实现用户交互的关键机制。其中,事件冒泡与事件委托是优化页面性能、简化代码的重要手段。事件冒泡是指事件从触发它的元素开始,沿着DOM树向上逐层传播至根节点的过程。通过阻止事件冒泡,可以控制事件的影响范围。而事件委托则是利用事件冒泡特性,在父元素上设置监听器来响应子元素的事件,这种方法减少了监听器的设置数量,特别适用于动态添加的子元素,提高了代码的可维护性和性能。掌握这两种技术,能帮助开发者构建更高效、更简洁的应用程序。
51 0
下一篇
无影云桌面