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

再谈前端优化——从实际项目优化说起 #14

Open
creeperyang opened this issue Dec 28, 2015 · 19 comments
Open

再谈前端优化——从实际项目优化说起 #14

creeperyang opened this issue Dec 28, 2015 · 19 comments

Comments

@creeperyang
Copy link
Owner

一直觉得前端优化是个挺复杂的东西(可能是我比较菜 😂 ):

  1. 某些优化方向是相对/相反的,实际中并没有简单统一的规则来直接套用。比如 减少http请求外联css/js文件 就是相对的。
  2. 优化在不同平台(PC/Mobile),不同网络状况,不同协议(http/http2)等等要侧重的东西都有所不同,规则可能有所变化。
  3. 优化并不是独立的系统,可能要考虑到代码维护,可读性等等其它因素。
  4. ...
@creeperyang
Copy link
Owner Author

1. 避免无效/多余请求

无效请求就是浪费,如果发生在网页请求开始阶段,会极大影响首屏渲染。

1.1 避免不必要的重定向

301302303/307 重定向比较常见,一般用于SEO及其它一些场合。但是不必要的重定向浪费了大量时间(一次往返+其它时间)。

这些不必要的重定向可能是无意识的(意想不到的),比如url末尾带不带/:

302

如上,当访问domain.com/fuzzy时,框架/HTTP容器根据url rewrite规则发出了30X响应,把我们重定向到了domain.com/fuzzy/。那么,浏览器对domain.com/fuzzy的请求就是被浪费的。

302details

上图是请求domain.com/fuzzy的时间消耗分布图,可以看到除DNS lookupinitial connection之外,其它的可能都是被浪费的时间。

对带不带trailing slash的处理:

  1. 推荐应该宽容处理(即带与不带响应相同内容而不是响应跳转)。
  2. 如果需要区分,请前后端设置链接时保证slash根据设置被带上或被移除。

具体情况具体分析,但从前端到后端,都应努力避免不必要的跳转!

1.2 避免404

除了API有意返回404,一般来说,静态资源返回404都是浪费带宽,可能会拖延页面的渲染时间。

CSS和JS之类的资源不必谈,因为大家应该都会注意到,重点想说的是**favicon**。

请求网址图标是浏览器的默认行为,其实前端开发时,我们可能会经常看到请求**favicon**而导致的404(因为开发阶段一般不会有放置图标)。

github为例:

<link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">

github 这就是我们看到地址栏旁的网站图标。当我们访问某个网站,浏览器总是会去请求这个图标,如果不正确设置那么就会一次次的404。

下面讲为什么要注意避免404呢?

  1. 404请求注定浪费的一次TCP往返时间+其它时间;
  2. 浏览器解析渲染网页是个复杂的系统,牵一发而动全身。现代浏览器对同一服务器最多开6个TCP连接来并发下载。404占用了某个TCP连接,会导致其它的请求被延迟。
  3. 可能会影响后端log日志等等。

1.3 正确设置标签的src属性

<el src=''></el>在浏览器里的行为可能完全不是你想的那样。

当你的网页中有<img src='' />时,会发生什么事呢?你可能以为只是多了个标签,之后设置src为有效地址即可正确显示图片,这期间不会有任何副作用。

naive 😂 仅仅以IE为例,低版本的IE碰到这个标签_会向页面所在的目录发请求_。是不是很震惊?

高兴的是,这种行为被HTML5规范了,现代浏览器都不会再发出请求。不幸的是,类似的<script src=""><link href="">的行为并没有被规范。永远不要把自己的想法强加在浏览器身上(即,不要想当然)。

@creeperyang
Copy link
Owner Author

2. 资源及其规划

这里的资源主要指JS/CSS/Image,其它音视频等资源暂不讨论。

2.1 资源尽量小,启用压缩

资源的大小是影响整个请求时间的绝对因素(更长的content download时间)。

  1. 图片压缩到合适大小,清晰度。为不同设备准备不同分辨率的图片。
  2. 对文本内容启用gzip压缩。

content-download

如上,一张错误提示的gif图片,大小83KB,超过95%的时间用在下载内容(蓝色块)上。

此外,gzip对文本的压缩效率很高,压到原内容的**20%-30%**也不足为奇:

gzip

如上,原文件36KB,gzip压缩后仅仅9.3KB。

2.2 CDN与域名收敛

CDN是个好东西!

CDN(内容分发网络)能够加速静态资源,原理就是提供分发网络(不同地理位置大量节点),在用户请求某资源时动态定位到最近节点,由最近的节点响应用户。

CDN与主站不在同一域名,可以避开浏览器同一域名最大6个TCP连接的限制,提高并发下载能力。

但我们知道,域名解析是需要时间的,我们需要控制统一页面中出现的域名数。一般来说,主站+CDN两个域名比较合理。

2.3 合理设计缓存

cache

善用缓存,让你的网页“秒开”。

  1. 对图片而言,由于内容固定,我们几乎可以用缓存让它永不过期。除去用户第一次访问,之后浏览器都会从本地加载。
  2. 对CSS和JS来说,缓存需要考虑更多一点东西,比如版本迭代,增量更新等等。

CSS和JS避不开的问题是文件合并,包括图标图片的sprite也是同样的。合并必须和缓存综合考虑。

2.4 合理的文件合并

这里加上了限定语_合理的_,因为文件合并 并不总是起正效用的,更多请看下一小节。

文件合并可以减少HTTP请求——这是正效用的原因。

一个正面例子是雪碧图:

2.5 文件合并和缓存规划

首先来看张chrome network的截图:

multi scripts

我们看到,页面引入了大量脚本(位于CDN),然后(后面的)脚本的timeline中出现了比较长的灰色块(可能也比较少见)。

gray block

灰色块代表什么?

Stalled:Time the request spent waiting before it could be sent. 简单说,就是纯粹浪费在等待上的时间(从收到发出请求指令到可以发出请求),包括代理协商和等待可复用的TCP连接释放的时间。我们这里没有代理协商,所以都浪费在了等待TCP连接释放上。

联系之前说的浏览器同源下最大6TCP连接的限制,我们可以知道图中如此耗时的根源:同源下多个js下载请求,超过6个,后面的请求被挂起,等待正在使用的TCP连接释放

同时,我们可以看到,有时等待时间可以达到总时间的**50%**左右!!这就是合并文件的一个重要原因:减少HTTP请求。

那么,是不是把所有JS打包成一个bundle.js最好呢?这需要结合实际讨论。这里有3个因素:

  1. 缓存的有效性。web app通常不是一锤子买卖,持续更新发布是常见的。打包到一个文件,那么任何一点小变化都会导致整个文件变更,这意味着缓存经常失效。这时通常不如把文件划分合并为_不变的通用库_+_经常变的业务逻辑_两部分(或者更细地划分)更好。
  2. 按需加载的效率比较。因为并不是所有内容都是首页需要的,甚至不是某平台需要的,完全不合并,按需加载某些情况可能更高效。
  3. 实际需求:系统后台类的web app可能能接受更长时间的首屏loading,然后希望之后的交互流畅;有些则对首屏渲染时间要求极高。不同的需求对应不同的方案。

总之,资源/缓存规划是复杂的,没有一劳永逸的方案,需要因地制宜。

2.6 延迟下载

并不是所有资源在首页/首屏是必须的,是可见的。所以有些资源是可以延时下载的。

这里的延迟下载和上面的按需加载有点类似。特地列出来一是按需加载一般与JS强关联,二是延迟下载的典型_图片延迟下载_有广泛的应用。

对于多图片的网页(如电商网站),在首屏以外的图片由于不可见,没必要一开始就加载。用一张默认图片代替这些图片一可以提高网页加载速度,二可以节省带宽。

down res

down res2

对比上面两张图可以看到,48张图片中首屏只需要加载14张,这极大低加快了网页渲染速度。

@creeperyang
Copy link
Owner Author

3. 占坑,待续

@bluezhan
Copy link

继续,继续 ...

@eyea
Copy link

eyea commented Apr 20, 2017

继续,继续。。

@jawil
Copy link

jawil commented Apr 20, 2017

继续,继续 ...

@jawil
Copy link

jawil commented Apr 20, 2017

继续,继续 !!!

@overcache
Copy link

大佬,一年过去啦

@creeperyang
Copy link
Owner Author

@icymind 哈哈哈 😂 已经不知道写什么了

@AZmake
Copy link

AZmake commented Aug 2, 2017

@creeperyang,可以来个如何从零开始实现一个SPA应用,纯手工打造,只是这个过程有点漫长!

@qiaoqiaowang
Copy link

很受教,谢谢

@Chang1ng
Copy link

最近遇到一个Content Download加载很慢的情况,返回的内容总共44kb,前端vue页面请求时间偶尔会有2~5秒,很是诡异。但是单独访问后端接口,花费的时间都小于400ms.

@AceLeeWinnie
Copy link

@Chang1ng 我也遇到了这个问题,不知道时间浪费在哪儿了,最后你查到原因了吗

@Zero0331
Copy link

@Chang1ng 同遇到,我的情况更诡异, 本地开发环境正常;测试环境正常;同测试环境不同端口号下content download超过2s,导致页面渲染数据慢了一步,react项目;

@creeperyang
Copy link
Owner Author

追踪请求挂起深层原因的好文:

关于请求被挂起页面加载缓慢问题的追查

对类似问题的追查应该会有帮助。

@xu20160924
Copy link

@Zero0331 请问你的问题解决了嘛? 我现在也是本地测试环境都没有问题,就是线上加载巨慢, vue 工程

@wjinlong
Copy link

@Chang1ng 请问一下大佬查到原因了吗?

@WangXBruc
Copy link

@wjinlong I think you should check the network condition of the production environment first.
Maybe there are many processes share the bandwidth.

@zhuleyan
Copy link

@xu20160924 请问一下您最后是怎么解决的这个问题呀 我现在也遇到了这个情况 本地测试没问题 线上加载特别特别慢 我是react项目

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

No branches or pull requests