Zheaoli / weekly-share

MIT License
6 stars 0 forks source link

当我们聊前端性能优化时,我们在聊什么 #20

Open CoderMageFox opened 3 years ago

CoderMageFox commented 3 years ago

因为最近也在积极的准备面试内容,但是被人问到你前端优化到底优化了什么的时候,我发现我没有办法从一个系统的角度来回答这个问题。乘着今天刚好要写点东西,就聊聊这个吧。首先说明一下,以下的各种事项我都会引入自己的角度与项目进行阐述,迫于某些敏感信息,将使用字母代替项目名。

应该从哪个方向思考?

有一道很泛用的面试题,就是一个页面从输入地址到展示,经过了哪些步骤。其实这道题就可以大概拆分成七个步骤:

  1. DNS解析。
  2. TCP连接。
  3. 建立HTTP连接。
  4. 服务端拿到数据,返回响应。
  5. 浏览器拿到响应数据。
  6. 浏览器对报文做处理,并将其拆分为dom报文(生成domtree),css报文(生成cssom),并最终合成renderTree.
  7. 将renderTree用浏览器的渲染机制渲染出来。

看起来十分简单的七个步骤,我们可以大概拆分成三个部分。1,2,3为网络,4为服务器,5,6,7为浏览器做的事。这里就能得出我们的第一个结论:所有的前端优化都可以大致拆分为两个部分:**网络渲染**。(出的所有问题也可以这么分)

定量?

首先我们遇到的第一个问题是,一个网页怎么样才算性能好,怎么样才算性能不好。 在早期,大家是不太注重网页性能的。因为在那个刀耕火种的年代,网页的概念还仅仅只是一个'页面',大家都不太在意网页的卡顿,因为出现的原因全部可以归结于网络层面上。

如果说Gmail网页版的出现标志着WebApp的诞生,那么雅虎34条军规的出现就代表着网页性能开始被人们所关注。 从那个时候开始,我们会用去YSlow,ShowSlow等插件去给一个页面打分,从而判断一个页面的性能是不是合格。再后来,Chrome官方推出了LightHouse.起初,LightHouse只是Audit标签下的一个小功能,在后来的更新中变成了一个单独的标签。

这个小小的改动,也正是页面性能越来越重要的体现。

现在,只要你打开Chrome的开发者工具,点击LightHouse标签,就可以拿到一份当前网页的具体性能指标。 具体的指标可以直接参考:

https://web.dev/performance-scoring/?utm_source=lighthouse&utm_medium=devtools

在官方推出LightHouse以后,对于网页的性能是否合格这个问题,似乎就没有什么更多的争议了。

真的是这样吗?

定性?

但是有一个小小的问题:这些工具所关注的,主要是在网络层面和工程层面(主要是关注于首屏),而对于渲染层面并没有一个客观评价的方法。

比如,我现在在使用的语雀编辑页面,Performance标签下的几个属性分别为:

First Contentful Paint 2.5 s Speed Index 3.1 s Largest Contentful Paint 4.3 s Time to Interactive 3.3 s Total Blocking Time 590 ms

得分更是只有可怜的31分。 这有些反直觉。一个“富应用”的打开时间在5-10秒之间,其实在大家的认知里,已经是很优秀的性能了。 没错,LightHouse存在的问题是,它只能给“页面”打分,而不能给“WebApp”打分。

毕竟,每个前端都会碰到产品冲过来说,你这个东西怎么卡卡的/我这边显示的很慢/打不开。什么?你说你的首屏很快(First Contentful Paint 与Speed Index低)?我操作起来就是卡卡的,你是不是在蒙我?

我们当然可以说:“噢,我的页面得分已经很高了。”然后把产品打发走。

但是,有没有这样一个标准,能够准确的描述这种“用户体验满意度”呢?它似乎才是我们真正需要关心的性能。

RAIL模型:真实的Web性能体现

很多时候我们在做性能优化的时候,自己给自己设立了一个标准。 比如我自己的项目A,在早期做性能调试的时候,我给自己定的标准是所有操作不能低于55帧。 但是我后来发现一个问题:有些操作会增加JavaScript堆栈的运算量,有些操作又会加多渲染进程的工作量。这使得某些看起来合理的操作,在减少了一边时间的同时又增加了另外一边的时间。 那么这个权衡的线在哪?怎么样才算合理呢?我陷入了苦恼之中。

好在,Chrome团队早在2015年就思考过这个问题。他们意识到,提供工具永远无法解决WebApp复杂应用场景下的性能衡量,所以他们提出了Rail模型。

让我们扔掉那些乱七八糟的参数和打分,静下心来看看,当你作为一个用户来使用这个产品的时候,你的感受是什么样的?

R:Response

R指代Response。这个地方的Response不是指后端数据的反馈,而是指人机交互的反馈。 Response的关键点,在于“让用户察觉不出延迟”。用户是敏感的,当自己的操作与界面的反馈出现了时间断层,他们会立马察觉,并在心里调低对这个页面的评分。 在Google的Performance RAIL’s中,我们可以清晰的看到用户对响应延迟的敏感度:  

Delay User reaction
0 - 100 ms Instant (即时)
100 - 300 ms Slight perceptible delay (轻微的可察觉的延迟)
300 - 1000 ms Task focus, perceptible delay (任务重点,明显的延迟)
1000+ ms Mental context switch (**一样的上下文切换)
10,000+ ms+ I'll come back later... (我溜了)

How Users Perceive the Speed of The Web / RAIL中,原文是这么描写的:

100ms gives the feeling of instantaneous response Results feel immediate. Any longer and the connection between action and reaction is broken.

1000ms  keeps the user's flow of thought seamless. Things feel part of a natural and continuous progression of tasks. Beyond it, the user loses focus and attention. Beyond 10 seconds you’ve lost the user's attention.

换句话来说,用户的操作与反馈间隔时间不应该超过100ms。 如果摒弃原本的网络问题,前端从自身能做到的,减少操作与反馈时间用户体感的最典型例子,就是我们日常使用的Loading。

当你提交一些数据或者form,一个loading+提交防抖可以大幅度的提高用户体验。在没有loading的WebApp中,动不动就5秒以上的数据延迟会让用户觉得卡顿严重,而一个loading可以传达出“这是这次任务的结束,程序运行良好,正在提交”的感觉。

还有一个广泛应用的Response tricks,就是文件的Upload进度条。 在我国现行的宽带条件下,用户上传文件是一个很让人肝疼的事。特别是在我的项目B中,用户需要上传一个很大的Excel文件,并且需要等待很长时间客户端返回解析结果,并且客户端此时是没有响应,也不能给出大概处理时间的。

之前的做法是给出Loading,用户就只能看着loading转啊转,然后经常怀疑是不是卡住了,按一下刷新,一切全完了。

后来的做法是,给一个假的进度条。估算一个平均的处理时间和超时时间(比如最少需要处理20秒,20开始5秒轮询一次,2次后未响应则处理失败)。在这20秒内,进度条每秒钟走5%,最后一次走到99%。此时如果处理完成,那么顺利走到100%。在使用这个做法以后,就算是处理失败,用户也会耐心的等待完30秒服务端报错。就算是客户端最后没有报错,客户也会怀疑是自己电脑的问题导致卡在了99%(同时极大的降低了用户的投诉)

L:Load

**

jackyyyy-dev commented 2 years ago

催更催更