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

摘要:
前言 数据代表,即便在资源有缓存的状况下,页面首次访问的耗时也是非首次访问的两倍。 为何首次访问这么耗时呢,时间去哪里了?本文详细分析页面首次访问耗时的缘由。 常见的初始化 咱们先看看打开一个页面,须要通过那些流程。

前言

数据代表,即便在资源有缓存的状况下,页面首次访问的耗时也是非首次访问的两倍。前端

为何首次访问这么耗时呢,时间去哪里了?本文详细分析页面首次访问耗时的缘由。数据库

常见的初始化

咱们先看看打开一个页面,须要通过那些流程。可能会包括,外壳初始化,内核初始化,建立WebView,建立Renderrer进程,初始化V8 JS引擎,初始化IPC,初始化CC,初始化网络库,初始化文件系统,初始化数据库,启动ServiceWorker线程,DNS解析,建立网络链接,页面服务器初始化,等等。这些流程前端通常是看不见的。小程序

在讨论具体的耗时以前,咱们先约定,下文全部的数据都是基于Nexus 5手机。不一样的手机的性能数据差别极大,一些高端手机(好比,iPhone X),性能多是中低端机的好几倍。浏览器

外壳初始化

咱们先看看浏览器外壳的初始化,用户点击桌面图标启动浏览器,浏览器会进入一个状态机,按步骤初始化各个模块,不少模块的初始化会涉及网络,文件IO,JNI,等等操做,这些都会有必定的耗时。缓存

固然,全新安装首次启动,外壳初始化的过程当中,通常最耗时的是加载SO和JAR,其中使用DexClassLoader去加载JAR文件,在一些中低端机器,特别是Android 5.0之前的系统,耗时是以秒计算的,有些甚至能够达到10秒。非全新安装首次启动,加载SO和JAR的耗时会大幅降低,大概在500ms。性能优化

咱们为何须要关心浏览器启动的耗时呢?一些场景下,用户经过扫码或者点击桌面图标去访问页面,这个过程就会包含浏览器的启动流程,咱们有必要了解这其中发生了什么。服务器

对于内置浏览器内核的App,好比,支付宝,手淘,状况又是怎样的呢?咱们这边暂时没有支付宝和手淘的启动性能数据,但模块初始化,加载SO和JAR,这些流程都会有,时间不会很小。微信

在外壳初始化耗时方面,有没有一些比较好的解决办法呢?网络

最好的办法就是进程保活,如今国内不少手机厂商都会给微信,支付宝,等超级App去进程保活,用户在任务列表杀掉了应用,其实进程还在。ide

若是是多进程的状况,能够提早建立进程,好比,微信和支付宝的小程序,用户访问时能够直接使用预建立的进程。

内核初始化

咱们再来看看内核的初始化,与外壳的初始化相似,内核的初始化也须要加载SO和JAR,建立WebView和初始化各个功能模块。

在建立WebView方面,全新安装首次建立约1秒,非全新安装首次建立约300ms,第二次建立约15ms。

首次建立Renderrer进程,初始化IPC,初始化CC,这些耗时在百毫秒的级别;

V8 引擎相关的初始化耗时也在百毫秒的级别,其中首次NewContext要20ms。

总的来讲,首次访问加载SO和JAR通常须要500ms,建立WebView和走完内核流程通常须要消耗500ms,也就是说,提早初始化内核和预建立WebView加载一个URL,跑一趟内核流程,能够带来约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之内。

网络初始化

在网络初始化方面,通常内核网络库的初始化并不太耗时,耗时的是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,在业务初始化方面不必定会有性能问题,须要根据本身的实际场景,具体问题具体分析。

做者: 小扎zack

原文连接

相关文章
相关标签/搜索