Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0-h5优化 #1

Open
qumai152909 opened this issue Sep 23, 2020 · 0 comments
Open

0-h5优化 #1

qumai152909 opened this issue Sep 23, 2020 · 0 comments
Labels
0-优化 Improvements or additions to documentation

Comments

@qumai152909
Copy link
Owner

qumai152909 commented Sep 23, 2020

https://www.cnblogs.com/kunmomo/p/11556146.html webView是什么

https://tech.meituan.com/2017/06/09/webviewperf.html webView 详细 图片

前端优化总结

在过去PC和手机浏览器中,已经有无数的优化手段,总结起来无外乎以下几点:

  • 减少请求数量:合并资源,减少HTTP请求,懒加载,内联资源等
  • 减少请求资源大小:压缩资源,gzip,web图片,减少cookie等
  • 提高请求速度:DNS预解析,资源预加载,CDN加速等
  • 缓存:浏览器缓存,manifest缓存等
  • 渲染:css、js加载顺序,同构直出等

几乎所有的应用最先遇到的性能瓶颈都是网络请求,所以能减少请求的缓存就显得比较重要。

浏览器的缓存机制这里就不做赘述,主要有通过设置Cache-Control等HTTP请求头的方式,和PWA中利用Service Worker的方式。利用浏览器缓存机制,页面再次请求资源时,可以从缓存中获取,减少网络请求。

而数据方面的请求,可以通过localStorage进行数据的缓存,首次渲染时可以使用本地缓存数据,然后再请求更新。

通过以上手段可以使页面第二次被访问时,快速打开,但是第一次访问时,依旧存在慢的问题。

作者:Chersquwn链接:https://juejin.im/post/6844904021426176007

webview优化

webview是什么?

WebView是一个基于webkit引擎、可以解析DOM 元素,展现web页面的控件,

它和浏览器展示页面的原理是相同的,所以可以把它当做浏览器看待。

WebView是用于展示网络请求后的结果,也就是将url网络请求的结果展示在里面。

如果原生系统没有webview,则是无法渲染展示html的。

使用webview的好处?

原生APP是将页面的布局设计,以及业务代码打包,然后用户下载安装使用。而webview是通过加载html文件来进行页面的展示,当需要更新页面布局的或者业务逻辑变更时,如果是原生的APP,就需要修改前端内容后,升级打包,重新发布才可以使用最新的内容。

而通过webview方式的页面,则只需要修改html代码或者js文件(如果是从服务器端获取,只要新的文件部署完成),用户重新刷新就可以使用更新后的,无需通过下载安装的方式完成升级。

页面启动的过程

为什么H5页面的启动时间长?尤其是SPA应用?

从用户点击到页面渲染完成,大体上经历了一下过程:

初始化webview => 请求html => 解析html => 请求css和js => 渲染 => 解析和执行js => 请求数据 => 渲染 => 下载图片 => 渲染 => 页面显示可交互

  • 1,交互无反馈 (webview初始化)
  • 2,页面白屏(建立连接,接收页面,接收样式,渲染)
  • 3,页面基本框架出现,但是没有数据;页面处于loading状态 (下载解析执行脚本,接收数据,渲染)
  • 4,出现所需的数据

常规SPA应用中,通常在请求完并且执行js时,才会出现loading之类的画面,而在这之前都是白屏,用户体验就很差,尤其是网络慢的时候。那么怎么才能进行优化呢?

为什么WebView总是很慢

  • 在浏览器中,我们输入地址时(甚至在之前),浏览器就可以开始加载页面。
  • 而在客户端中,客户端需要先花费时间初始化WebView,初始化完成后,才开始加载。

而这段时间,由于WebView还不存在,所有后续的过程是完全阻塞的。

webview初始化:

webview 是移动端浏览器实例,几乎具备 PC 端浏览器的绝大多数能力,客户端在使用 webview 打开 H5 页面前,需要实例化 webview 对象,其初始化的过程在 android 系统中需要大约 500ms 以上的时间。

有一种优化手段是:使用对象复用机制,提前创建 webview 对象池,需要使用 webview 时,直接从池中获取初始化完毕的对象,这种方式,可以避免每次打开 H5 页面都要初始化 webview 实例,从而提升页面打开速度。

L P App的webview

App Webview 目前没有做预加载,点击进入H5页面时,才会初始化webview,关闭 H5 页面时会销毁 webview,再次打开时重新初始化。

目测初始化 Webview 的时间 ,**总白屏时间是几秒级的,**从 native 进入 H5 和 H5 进入 H5 页面,时间差异明显, 冷热启动的具体耗时要客户端才能debug详细数据。

总结:

  • 初始化Weview预加载,可以极大缩短白屏等待时间(和翔宇沟通过,他们也有意向做 webview 的前置)
  • 启动webview进程过程中,可以由 native 代理页面的网络请求,等启动完毕,资源也请求好了(客户端表示目前访问时不清楚要下载哪些资源,如果有列表就可以做)
  • loading时间可以忽略不计,目前 C 端 H5 页面是服务端渲染,不是前端渲染

业界已有实践的方法

各种方法,总结起来都是围绕两点:

  1. 在使用前预先初始化好WebView,从而减小耗时。
  2. 在初始化的同时,通过Native来完成一些网络请求等过程,使得WebView初始化不是完全的阻塞后续过程。

1,提前初始化全局webView

  • 当App刚启动时,就初始化全局webView并隐藏,
  • 当用户访问了webView时,直接使用这个 webView加载对应网页。

**优点:**这种方法可以比较有效的减少WebView在App中的首次打开时间。当用户访问页面时,不需要初始化WebView的时间。

**缺点:**是需要额外消耗内存。还有需要webView切换时需要清除页面痕迹,容易造成内存泄漏。

2, 设置webView缓冲池

App启动后,在webView的缓冲池,初始化多个webView。

需要加载网页时,可以去缓冲池中去取出新的webView。不需要时就可以直接销毁,同时初始化新的webView放进缓冲池中。

缺点:是相比而言需要更大的额外内存消耗。但是确保减少webView初始化消耗的时间和降低清除页面所造成的内存泄漏

3, 客户端代理数据请求

在初始化webview的同时,通过 Native 来完成一些网络请求等,然后再回传给WebView,使得 WebView初始化不是完全的阻塞后续过程。

特点:

此方法虽然不能减小WebView初始化时间,但数据请求和WebView初始化可以并行进行,总体的页面加载时间就缩短了;缩短总体的页面加载时间。

建立连接-优化

在页面请求的数据返回之前,主要有以下过程耗费时间:

  • DNS
  • connection
  • 服务器处理

DNS

DNS优化:WebView采用和客户端API相同的域名

DNS会在系统级别进行缓存,对于WebView的地址,如果使用的域名与native的API相同,则可以直接使用缓存的DNS而不用再发起请求。

以美团为例,美团的客户端请求域名主要位于api.meituan.com,然而内嵌的WebView主要位于 i.meituan.com。

当我们初次打开App时:

  • 客户端App首次打开都会请求api.meituan.com,其DNS将会被系统缓存。
  • 然而当打开WebView的时候,由于请求了不同的域名,需要重新获取i.meituan.com的IP。

根据统计,至少10%的用户打开WebView时耗费了60ms在DNS上面,如果WebView的域名与App的API域名统一,则可以让WebView的DNS时间全部达到1.3ms的量级。

dns-prefetch

DNS Prefetch 是一种DNS 预解析技术,浏览器会在加载网页时,对网页中的域名进行解析缓存,这样在你单击当前网页中的连接时就无需进行DNS的解析,而是直接利用缓存,减少用户等待时间,提高用户体验。


当浏览器从第三方服务跨域请求资源的时候,在浏览器发起请求之前,这个第三方的跨域域名需要被解析为一个IP地址,这个过程就是DNS解析DNS缓存可以用来减少这个过程的耗时,DNS解析可能会增加请求的延迟,对于那些需要请求许多第三方的资源的网站而言,DNS解析的耗时延迟可能会大大降低网页加载性能。

dns-prefetch可帮助开发人员处理DNS解析延迟问题。

HTML <link>元素通过dns-prefetch的rel属性值提供此功能。然后在href属性中指定跨域域名:

<link rel="dns-prefetch" href="https://fonts.googleapis.com/">

每当站点引用跨域域上的资源时,都应在<link>放置dns-prefetch提示


这个功能有个默认加载条件,所有的a标签的href在chrome,firefox包括高版本的IE都会自动去启用DNS Prefetching,也就是说,你网页的a标签href带的域名,是不需要在head里面加上link手动设置的。

​ 但有一点他没有提到,a标签的默认启动在HTTPS不起作用。需要如下设置开启

<meta http-equiv="x-dns-prefetch-control" content="on">

作者:zyy1688链接:https://juejin.im/post/6844903612829663245

DNS 的预解析

现代浏览器都支持 DNS 的预解析,学名:DNS Prefetching。用法也很简单,就是在html代码里加入这样的 link 标签

<link rel="dns-prefetch" href="//delai.me">  

注意

  • 首先,dns-prefetch仅对跨域上的DNS查找有效,因此请避免将其用于您当前访问的站点。

    这是因为当浏览器解析到当前Link元素内容时,您站点域背后的IP已经被解析。

  • 其次,还可以将dns-prefetch(和其他资源提示)指定为HTTP标头:

    Link: <https://fonts.googleapis.com/>; rel=dns-prefetch
  • 第三,考虑将dns-prefetch与preconnect结合

    尽管dns-prefetch仅执行DNS查找,但preconnect会建立与服务器的连接。如果站点是通过HTTPS服务的,则此过程包括DNS解析,建立TCP连接以及执行TLS握手。将两者结合起来可提供机会,进一步减少跨源请求的感知延迟。您可以安全地将它们一起使用,如下所示:

    <link rel="preconnect" href="https://fonts.googleapis.com/" crossorigin>
    <link rel="dns-prefetch" href="https://fonts.googleapis.com/">

之所以把dns-prefetch放在preconnect之后,是因为浏览器对dns-prefetch的支持比对preconnect的支持要好。不支持preconnect的浏览器仍然可以通过回退到dns-prefetch来获得更多好处。

正确的使用姿势

1.对静态资源域名,做手动dns prefetching。
2.对js里会发起的跳转、请求做手动dns prefetching。
3.不用对超链接做手动dns prefetching,因为chrome会自动做dns prefetching。
4.对重定向跳转的新域名做手动dns prefetching,比如:页面上有个A域名的链接,但访问A会重定向到B域名的链接,这么在当前页对B域名做手动dns prefetching是有意义的。

总结:

预解析的实现:

\1. 用meta信息来告知浏览器, 当前页面要做DNS预解析:

\2. 在页面header中使用link标签来强制对DNS预解析:

注:dns-prefetch需慎用,多页面重复DNS预解析会增加重复DNS查询次数。

多域名

Chrome 等现代化浏览器,都会有同域名限制并发下载数的情况,不同的浏览器及版本都不一样,简单的情况如下:一般为6个以内。

使用不同的域名,可以最大化下载线程,但注意保持在 2~4 个域名内,以避免 DNS 查询损耗(会使DNS解析负担过重)。

例如,动态内容放在 csspod.com 上,静态资源放在 static.csspod.com 上。这样还可以禁用静态资源域下的 Cookie,减少数据传输,详见 Cookie 优化。cookie隔离

浏览器对并发请求的数目限制是针对域名的,即针对同一域名(包括二级域名)在同一时间支持的并发请求数量的限制。如果请求数目超出限制,则会阻塞。因此,网站中对一些静态资源,使用不同的一级域名,可以提升浏览器并行请求的数目,加速界面资源的获取速度。

网络优化

大致方向:

  • 1, 保证接口设计的合理性,必要时合并网络请求,减少请求次数;
  • 2,网络缓存(在弱网或者是无网络的情况下,因为有缓存的支持,不至于 APP 打开一片空白,这给用户更好的体验。)
  • 3,数据压缩,如 Gzip 压缩 request 和 response,减少网络流量传输。

  • 配置浏览器缓存,主要指强缓存和协商缓存,可以大大减少网络时延,减少服务器压力。
  • 资源压缩,前端有成熟的工具可以对生成的 js、css 等产物进行压缩,若有必要可以还考虑 gzip 压缩,获得更大的压缩比。
  • 资源请求合并,过多分散的资源包会产生过多的网络请求,但也不能随意合并,最佳的方式是按照页面或者模块进行划分,并配置 async 属性来异步加载 script 脚本。

预缓存

前情提要

App应用的功能代码,通常在用户访问之前,就已经以安装包的形式,通过应用市场下载安装好了。

而网页应用的功能代码(静态资源),则是在用户实际访问时,才实时下载运行。

这一『用时下载』的特点是一把双刃剑,既带来了实时更新的灵活性,也造成了应用启动的延迟,导致网页应用启动速度远远落后于App应用,造成交互体验和用户转化短板。

预缓存概念:

由于静态资源具有确定性,因此可以先主动获取所需缓存的资源列表,并且在 Service Worker 安装阶段,就主动发起静态资源请求并缓存,这样一旦新的 Service Worker 被激活之后,缓存就直接能投入使用了。

这是一个资源预取的过程,因此静态资源的缓存方案也称为预缓存方案

  • 资源列表获取

H5 页面加速优化

有三个方向可以进行优化:

  • 页面启动白屏时间
  • H5 页面的交互体验,如响应流畅度
  • 页面渲染性能

静态资源优化

静态资源主要指 html,js 和 css 资源,对于单页应用而言主要是 js 和 css。

按需加载,对于单页应用,如果在首页,就把整个站点的资源全部下载,其实是不合理的,使用按需加载(懒加载)的方式可以有效提高首页性能。

骨架屏也是移动端首屏优化的一个重要手段,在页面数据未准备好的情况,相比与枯燥的白屏页面而言,展示骨架屏能给用户一个好的感官体验。但是如何生成质量高的骨架屏也是一个难点,需要综合考虑 ROI 来选择是否使用骨架屏。

资源加载顺序

  1. CSS的加载会在HTML解析到CSS的标签时开始,所以CSS的标签要尽量靠前。
  2. 但是,CSS链接下面不能有任何的JS标签(包括很简单的内联JS),否则会阻塞HTML的解析。
  3. 如果必须要在头部增加内联脚本,一定要放在CSS标签之前。

通常情况下,CSS不会阻塞HTML的解析,但如果CSS后面有JS,则会阻塞JS的执行直到CSS加载完成(即便JS是内联的脚本),从而间接阻塞HTML的解析。

ssr优化

还有另外一个完全不同思路来优化移动端 H5 页面打开速度,那就是服务端渲染,也称之为 SSR。

简单来讲就是,服务端将页面的 html 和数据提前组装好再传递给浏览器,浏览器只负责解析 html 和展示,因此首屏渲染较快。

但是会给服务端增加压力和复杂度,现实中需要综合考虑利弊以及 ROI 来选择是否使用 SSR 方案。

#我的优化实践

1, Webview 首屏优化

客户端建立 webview 复用池,预初始化 webview

2,静态资源预缓存

将变更不频繁的公用资源,通过map存放在App本地,直接从本地缓存中读取资源

3,公用静态资源统一存放

h5 公用的资源存放到 fe-lib-h5 项目中,多项目切换可利用缓存 。

多端公用

项目地址:http://gitcode.lietou.com/dev38/fe-global/fe-lib-h5

使用文档:http://gitcode.lietou.com/dev38/fe-global/fe-lib-h5/blob/master/README.md

fly-lib-h5:

h5公用静态资源库

  • 直接在 jsp 使用 fly-lib-h5 的项目链接即可
// 示例
<script>
  FeLoader.get(
    '//s.lietou-static.com/fe-lib-h5/v5/babel-polyfill/6.8.0/polyfill.min.js',
    '//s.lietou-static.com/fe-lib-h5/v5/react/16.8.6/react.min.js',
    '//s.lietou-static.com/fe-lib-h5/v5/react-dom/16.8.6/react-dom.min.js',
  );
</script>
  • 目录划分
- asset // 生产静态资源目录,npm run prd 编译后生成
- asset-dev // 开发静态资源目录,npm run dev 编译后生成
- src // 资源文件总目录
	- react // 资源目录(资源必须创建目录管理)
		- 16.8.6 第三方资源按照版本号创建次级目录
			- react.min.js
			- react.js
  - react-dom
  	- 16.8.6
  		- react-dom.min.js

4,CDN节点响应延时偏高

调整 CDN 部署策略,启用 s.lietou-static.com (H5资源独立域名,不兼容IE9及以下浏览器)

测量指标:

首包时间,可用性,总下载字节数,总下载时间,DNS时间(55.36%), 建立连接时间,内容下载时间,首屏时间

TTFB(waiting时间)提高明显

5,页面结构 (HTTP)

  • 1,在入口页添加 dns-prefetch meta 标签

对于会使用到的域名,添加 “dns-prefetch”,提前执行dns解析,只需要在入口页面添加

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="x-dns-prefetch-control" content="on"> // 开启dns-prefetch
  <link rel=dns-prefetch href="https://concat.lietou-static.com"> // 需要预解析的域名
  <link rel=dns-prefetch href="https://image0.lietou-static.com">
  <title>title</title>
  <%@ include file="/includes/v5/resources_header.html" %>
  • 2, 预先建立 connect 通道 :

使用 “preconnect” 建立 connect 通道,当请求对应资源时,会直接使用建立好的通道

<!-- resources_header.html -->
  <meta charset="UTF-8">
  <meta http-equiv="x-dns-prefetch-control" content="on">
  <link rel=dns-prefetch href="https://concat.lietou-static.com">
  <link rel=dns-prefetch href="https://image0.lietou-static.com">
  <link rel="preconnect" href="//s.lietou-static.com" />
  <link rel="preconnect" href="//image0.lietou-static.com" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0,
maximum-scale=1.0, user-scalable=0">
  • 3, 使用 prefetch标签预加载下一页需要使用的资源

    判断用户访问的下一页面,如果是极大几率发生的结果,可以使用 “prefetch” 预加载下个页面的资源,浏览器普遍会在后台保持 5 分钟,切换页面也不会丢失加载

    <link rel="prefetch" href="/path/to/script.js">

6,多域名

资源多域名,提高并行资源加载速度(已启用):图片资源前端静态资源为 2 个域名

目前使用的前端资源域 concat.lietou-static.com 要兼容 IE7,8,9 用户的访问,部署方式导致目前节点偏少。

可以启用新域名(s.lietou-static.com),针对手机高版本浏览器,测试新的cdn部署方式,不需要兼容IE用户


静态资源和图片使用了不同域名:s.lietou-static.com ; concat.lietou-static.com image0.lietou-static.com (图片服务器)

🌲🌲🌲🌲🌲🌲🌲🌲🌲:https://learnku.com/docs/f2e-performance-rules/use-a-domain-name-without-cookies/6392

7,js优化

DOMContentLoaded 表明页面阻塞代码偏多

❇️维持页面基础交互外,js代码过多

  • loader.js(cdn回源)
  • femonitor.min.js(前端错误收集)
  • dlog.js(安全部门检测用户行为,页面 onLoad 之前就开始发送请求)
  • 利用document.write获取微信分享签名的代码(很多页面不需要,可以移动到api调用时,但单页面可能会有多次调用)
  • user.behavior.js(未知用途)
  • hm百度分析代码
  • gio分析代码(growingIO)
  • stat.js(页面 onLoad 之前就开始发送请求)
  • 百家号推送代码

❇️代码放置位置不规范

  • dlog.js放置到div中
  • head 标签内在外联 css 文件下面放置内联 js 代码
  • 多个请求没有合并一次调用 FeLoader

❇️common.js 代码量过大,导致解析时间平均占用接近600ms,大小 263KB

压缩 common.js 的代码,目前打包到 common.js 中的代码是多次引用的代码包及基础js,这减小了平均页面打开时间,对初次打开不友好

实践结果

本人参与的项目在 H5 页面只针对静态资源和数据请求进行了优化,完成后获得效果还是较为理想的,见下图。

绿色线是优化之后页面打开的平均白屏时间,蓝色是优化前的平均白屏时间,能看到优化成效还是相当可观的,如果能将 webview 的初始化时间也优化掉,基本上能达到页面秒开。


对于会使用到的域名,添加 “dns-prefetch”,提前执行dns解析,只需要在入口页面添加


以上是结合自己项目以及以往的经验总结的较为常规的针对移动端体验优化的思路,比较浅显,其实每一个优化思路虽然说起来简单,但是在实践中会因为各种因素(如投入产出比,前后端资源协调等)导致夭折,而且优化思路也需要分场景,需要因地制宜选用不同的方案。

参考链接:

1, https://www.nihaoshijie.com.cn/index.php/archives/795/

2, https://www.ershicimi.com/p/072bbd14a6def2c2faed2128b7f8b445 来自阿里大佬的关于移动端体验优化经验总结 🧚‍♀️🧚‍♀️🧚‍♀️🧚‍♀️🧚‍♀️🧚‍♀️

3, https://lavas-project.github.io/pwa-book/chapter05/4-precache.html 预缓存文档

4, https://zhuanlan.zhihu.com/p/77144845 知乎-预加载-预缓存

5,https://developer.aliyun.com/article/762969 数据监控平台

6, https://tech.youzan.com/dns-prefetching/ 域名预解析

7, https://cloud.tencent.com/developer/article/1046674 dns-prefetch 简介 🧚‍♀️

8, barretlee/performance-column#3 GitHub dns-prefetch 🧚‍♂️🧚‍♂️🧚‍♂️🧚‍♂️🧚‍♂️🧚‍♂️🧚‍♂️🧚‍♂️🧚‍♂️

9, https://learnku.com/docs/f2e-performance-rules/use-multiple-domain-names/6388 前端优化35个军规🐎🐎🐎🐎🐎🐎🐎🐎🐎🐎

@qumai152909 qumai152909 added 1-JS Something isn't working 0-优化 Improvements or additions to documentation and removed 1-JS Something isn't working labels Sep 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0-优化 Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

1 participant