Skip to content
New issue

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

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

Already on GitHub? # to your account

无线性能优化--从网络请求入手优化产品体验 #53

Open
jiangjiu opened this issue Oct 26, 2018 · 0 comments
Open

无线性能优化--从网络请求入手优化产品体验 #53

jiangjiu opened this issue Oct 26, 2018 · 0 comments

Comments

@jiangjiu
Copy link
Owner

从网络请求入手优化产品体验

以用户为中心

对于web产品来说,加载时间和快速响应是两个影响体验的重要指标。

加载时间很好理解,1s打开的页面肯定会比3s打开的页面体验好

那么响应时间呢?

根据GOOGLE的RAIL模型量化描述:

操作响应---延迟时间 用户反应
0 - 16 毫秒 人们特别擅长跟踪运动,如果动画不流畅,他们就会对运动心生反感。
用户可以感知每秒渲染 60 帧的平滑动画转场。也就是每帧 16 毫秒(包括浏览器将新帧绘制到屏幕上所需的时间,留给应用大约 10 毫秒的时间来生成一帧。
0 - 100 毫秒 在此时间窗口内响应用户操作,他们会觉得可以立即获得结果。
时间再长,操作与反应之间的连接就会中断。
100 - 300 毫秒 用户会遇到轻微可觉察的延迟。
300 - 1000 毫秒 在此窗口内,延迟感觉像是任务自然和持续发展的一部分。
对于网络上的大多数用户,加载页面或更改视图代表着一个任务。
1s+ 超过 1 秒,用户的注意力将离开他们正在执行的任务。
10s+ 用户感到失望,可能会放弃任务;之后他们或许不会再回来。

从RAIL模型我们可以看出,响应时间有几个关键的节点:

用户可感知60帧动画

动画分别运行在60FPS和30FPS,用户会有明显的感知差异;
当动画帧率忽高忽低,用户会觉得卡顿、掉帧,这是很不好的动画体验。
由于动画FPS和本文的优化无关,就不展开了。

100ms时间点

当用户触发一个操作,应该在100ms之内给与用户反馈,不然会有轻微的延迟感。

这给我们的启示是什么呢?

  1. 像点击按钮触发弹窗这样的业务逻辑,应该保证在100ms内完成。
  2. 考虑到用户操作路径,应该确保每一步操作都有快速反馈。

百度APP跳转体验问题

百度APP轻框架中,使用a标签跳转或者location.href进行页面跳转时,由于要加载下一个页面的html资源,整个页面都处于停滞状态,感觉就像页面卡住了。

这样的体验就不符合100ms原则,但是很容易做优化。

来看下面两个的例子:

delay
上图是通过location.href进行跳转的方式。

fast-react
上图是调起另外一个轻框架进行打开。

通过上面两个例子可以看到,直接跳转延迟十分严重;使用schema调起,用户会得到即时反馈

所以,在活动中心、福利中心等入口,进入活动时,应该使用schema调起的方式进入

(初始化一个schema框架会增加60ms左右的耗时,但换来的是良好的反馈,这个时间是值得花费的。)

在一个活动不同页面进行跳转的时候,因为log、缓存、loading图、BF Cache等更细粒度的控制,使用schema调起可能会引入新的问题,就可以忽略。

300ms时间点

旧版的Safari存在经典的300ms延迟问题,这会让用户感觉到每一次点击操作都有延迟。

不过现代浏览器都做了优化,而且我们也引入了faskclick库进行兼容,这个时间暂时无需关心。

1000ms时间点

一秒钟又是一个关键节点。

在此窗口内,延迟感觉像是任务自然和持续发展的一部分。
对于网络上的大多数用户,加载页面或更改视图代表着一个任务。

这说明,loading状态应该尽可能在1s之内结束,考虑到3G网络RTT较高,我们起码应该限定4G网络以上,应该在1s内结束loading状态(也就是FMP-FCP的限定时间)。

10秒以上

用户已经放弃。fast 3G情况下,我们的活动页面的可交互时间都在5s内完成,所以无需关心。

优化关键渲染路径

HTTP2.0

没什么好说的,划时代的更新,直接开启。

网络请求现状

我们来看一个拆红包活动的典型网络请求流程:

可以看到,总体资源加载达到了800kb,资源(尤其是图片)过大,可以通过响应式图片方案解决掉。

最关键的是加载顺序

加载顺序

上图可以看到,涉及到首屏渲染的资源,没有在第一时间发起请求,而是慢慢延迟,排队进行请求。

对于http2的多路复用来说,这是极大的浪费。

超理想状态

在最理想的状态下,所有的资源只通过一轮请求就完全获取。
然而这又是不现实的,因为第一个请求永远是html文件,需要将所有资源都内联至html中,包括图片。
(大误,Server Push了解一下)

现实中的理想状态

在可实现的状态下,所有资源需要两轮请求。
第一轮是html请求,第二轮是其他首屏渲染需要的请求。
如果有第三轮第四轮,应该都是首屏业务无关的请求了,比如非首屏的异步组件、非首屏的图片资源等。

FOX方案

在FOX方案中,按照上述的理想状态做了优化:

保证所有的首屏资源都可以在两轮请求中获得。
这涉及到HTTP2协议支持、preload标签、webpack拆包策略等,不再赘述。

首屏接口并行化

做到上面这样,难道就结束了吗?

还差得远。

我们现在的活动,都是通过首屏数据直接注入至html中返回给前端的,这样有一些好处(?),但是弊端也存在。

首屏数据注入的问题

  1. 前后端耦合
    注入一定要通过模板引擎实现,但是php和Node.js不同的语言有不同的模板语法、扩展名,如果后端团队不确定的情况下,这个需要一定的成本修改。

  2. 页面闪动?
    起初,做首屏数据注入是为了解决数据闪动的问题, 但是从原理和实际测试来看,用接口做数据返回也可以解决,所以这不是理由。

  3. 真的会快?
    对于一个CSR的应用来说,数据返回有多快,并不是页面呈现快的直接相关原因。如果后端数据读取可以做首屏接口并行化,虽然数据返回变慢了,但是页面渲染实际上却加快了。

使用首屏接口的好处


观察这张图,图中有一个index接口,实际上后端服务做了100ms的延迟。

可以看到这个请求消耗了122ms,但是真正阻塞渲染的请求实际上是san.js的159ms,这只是个demo,正常业务中,一定会有更大尺寸的js、css文件,请求时间会更长。

(所以看看打包后的js、css,不要超过30k?)

相比首屏数据注入,这样做的好处是,请求html本应该耗时100+ms,因为html和首屏数据分离,让html可以更快的返回,就可以更快的加载第二轮资源请求。首屏接口本身并不阻塞渲染。

而且,本身处于同域的请求、keep alive/h2复用,会让首屏接口到达时间缩短。

所以,虽然数据返回变慢了,但是实际渲染完成的时间却是提前了。

域名收敛

http2时代,就不需要多个域来增加并发请求了,因为实际环境中,查找dns、TLS握手的时间远比想象的时间要长(50ms-5s不等)。
FOX方案保证构建出来的所有静态资源都在同一个cdn域下,这点无需开发者关心。

First Contentful Paint

得益于请求接口并行、关键渲染路径的优化,FCP会达到理想状态的极限
这个时间差不多是网络时延+30-120ms(parse html)左右,几乎不可能再优化了(UDP协议不太服气)。

在wifi、4g网络状态下,首次内容绘制的时间都可以在30ms-200ms内完成,相比动辄几百甚至一秒的白屏时间,用户体验的提升巨大

preload/dns-prefetch/prefetch

首屏关键图片、所有的js、css都做了preload处理。
san的异步组件设计完成后(版本3.7.0),还可以使用prefetch进行预加载。
常规的dns-prefetch开发者手动指定一次即可。

总结

优化产品体验,网络部分值得深入研究。

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

1 participant