谈谈前端性能优化-面试版

前言

当我们去面试的时候,很大概率会被面试官问这么一个问题:你有尝试过对项目做性能优化吗?或者你了解哪些性能优化的方法?听到这个问题的你可能是这样的:

似曾相识但又说不清楚,往往只能零散地说出那么几点,难以做到有条理的回答。那么,本文就带你简单了解前端性能优化的几个主要方面,旨在抛砖引玉。

一、资源的合并和压缩

请求过程中一些潜在的性能优化点:

  • dns是否可以通过缓存减少dns查询时间?
  • 网络请求的过程如何走最近的网络环境?
  • 相同的静态资源是否可以缓存?
  • 能否减少http请求的大小和次数?
  • 能否进行服务端渲染?

总结: 深入理解http请求的过程是前端性能优化的核心。

优化核心

  • 减少http请求数量;
  • 减少请求资源的大小;

google首页案例学习

  • html压缩;
  • css压缩;
  • js的压缩和混乱;
  • 文件合并;
  • 开启gzip

1.html压缩

HTML代码压缩就是压缩一些在文本文件中有意义,但是在HTML不显示的字符,包括空格制表符换行符等,还有一些其他意义的字符,如**HTML注释**也可以被压缩;

一个简单的计算:

google的流量,占到整个互联网的40%,预计2016年全球网络流量将达到1.3ZB(1ZB = 10^9TB),那么google2016年的流量就是1.3ZB * 40%,如果google1MB请求减少一个字节,**每年可以节省流量近500TB**流量。

如何进行html压缩

  • 使用在线网站进行压缩;
  • nodejs提供的html-minifier工具;
  • 后端模板引擎渲染压缩;

2.css代码压缩

分为两部分:

  • 无效代码的压缩;
  • css语义合并;

如何进行css压缩

  • 使用在线网站进行压缩;
  • 使用html-minifierhtml中的css进行压缩;
  • 使用clean-csscss进行压缩;

3.js压缩与混乱(丑化)

包括:

  • 无效字符的删除(空格,回车等);
  • 剔除注释;
  • 代码语义的缩减和优化;
  • 代码保护(如果代码不经处理,客户端可直接窥探代码漏洞);

JS压缩与混乱(丑化)

  • 使用在线网站进行压缩
  • 使用html-minifierhtml中的js进行压缩;
  • 使用uglify.js2js进行压缩;

4.文件合并

文件合并的好处:

4.png 左边的表示使用http长链接keep-alive但不合并请求的情况,需要分三次去获取a.jsb.jsc.js;右边是使用长链接并且合并请求的情况,只需要发送一次获取合并文件a-b-c.js的请求,就能将三个文件都请求回来。

不合并请求有下列缺点:

  • 文件与文件之间有插入的上行请求,会增加N-1个网络延迟;
  • 受丢包问题的影响更严重:因为每次请求都可能出现丢包的情况,减少请求能有效减少丢包情况;
  • keep-alive本身也存在问题:经过代理服务器时可能会被断开;

文件合并存在的问题

  • 首屏渲染问题:当请求js文件的时候,如果页面渲染只依赖a.js文件,由于文件合并,需要等待合并后的a-b-c.js文件请求回来才能继续渲染,这样就会导致页面渲染速度变慢。这种情况大多出现在现代化的前端框架,如Vue等的使用过程中;
  • 缓存失效问题:合并后的文件a-b-c.js中只要其中一个文件(比如a.js)发生变化,那么整个合并文件都将失效,而不采用文件合并就不会出现这种情况;

使用建议

  • 公共库合并:将不经常发生变化的公共组件库文件进行合并;
  • 将不同页面的js文件单独合并:比如在单页面应用SPA中,当路由跳转到具体的页面时才请求该页面需要的js文件;

如何进行文件合并

  • 使用在线网站进行文件合并;
  • 使用nodejs实现文件合并;
  • 使用webpack等前端构件化工具也可以很好地实现;

二、图片相关的优化

有损压缩过程: 一张JPG图片的解析分别要进行:

  • 颜色空间的转换:从RGB的颜色空间转到其他的颜色空间 ;
  • 进行重采样:区分高频和低频的颜色变换;
  • 进行DCT过程:对高频的颜色采样结果进行压缩,这样压缩的收益会比较大;
  • 再对数据进行量化;
  • 最后进行编码(encoding);

最终得到JPEG-Compressed Image Data,即真正显示出来的JPG图片。虽然这是一种有损压缩,但是很多情况下,这些损失的数据并不影响显示;

png8/png24/png32之间的区别

  • png8256色 + 支持透明;
  • png242^24色 + 不支持透明;
  • png322^32色 + 支持透明;

不同格式图片常用的业务场景

  • jpg有损压缩,压缩率高,支持透明;应用:大部分不需要透明图片的业务场景;
  • png支持透明,浏览器兼容好;应用:大部分需要透明图片的业务场景;
  • webp2010年由谷歌推出)压缩程度更好,在ios webview中有兼容性问题;应用:安卓全部;
  • svg矢量图,代码内嵌,相对较小,用于图片样式相对简单的场景;应用:比如logoiconfont

1.图片压缩

针对真实图片情况,舍弃一些相对无关紧要的色彩信息,对图片进行压缩;

2.css雪碧图

将网站上用到的一些图片整合到一张单独的图片中,从而减少网站HTTP请求数量。原理为:设定整张雪碧图可示区域,将想要显示的图标定位到该处(左上角);**缺点:**整合图片比较大时,一次加载比较慢。参考 前端进阶面试题详细解答

如天猫的雪碧图:
很多情况下,并不是所有的小图标都放在一张雪碧图中,而是会适当进行拆分。现在使用雪碧图的场景比较少了。

自动生成雪碧图样式

3.网页内联图片(Image inline

将图片的内容内嵌到html当中,减少网站的HTTP请求数量,常用于处理小图标和背景图片。网页内联图片写法为:

 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..." alt="">

缺点:

  • 浏览器不会缓存内联图片资源;
  • 兼容性较差,只支持ie8以上浏览器;
  • 超过1000kb的图片,base64编码会使图片大小增大,导致网页整体下载速度减慢;

所以要根据场景使用,不过内联图片减少HTTP请求的优点还是很显著的。比如,在开发中小于4KB8KB的图片都会通过构建工具自动inlineHTML中,这种情况下Image inline带来的图片大小增长其实是比增加HTTP请求次数更优的。

4.矢量图SVGiconfont

使用iconfont解决icon问题

应尽量使用该方式,比如可以采用阿里巴巴矢量图库:

可以选择格式进行下载:

可以看到它们的大小有着明显的差异:

使用SVG进行矢量图的控制

SVG意为可缩放矢量图形(Scalable Vector Graphics)。SVG 使用 XML 格式定义图像。

5.webp

webp的优势体现在它具有更优的图像压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha透明以及动画的特性。在JPEGPNG上的转化效果都非常优秀、稳定和统一。安卓上不存在兼容性问题,推荐安卓下使用。

以下为淘宝网首页请求的图片:

可以看到,图片中大量地添加了webp格式的选择。.jpg_.webp表示当浏览器支持webp时采用webp格式,否则采用jpg格式。

下面为B站首页的图片,可以看到基本都采用了webp格式:

同一张图片jpg格式和webp格式压缩率有着明显的差异:

可以通过在线网站将图片转换为webp

像图片这样的静态文件可以存放在CDN服务器上,让CDN服务器批量地将图片转换成Webp格式;

三、浏览器渲染引擎与阻塞

1.渲染的主要模块

版本一:

版本二:

一个渲染引擎主要包括:HTML解析器,CSS解析器,javascript引擎,布局layout模块,绘图模块:

  • HTML解析器:解释HTML文档的解析器,主要作用是将HTML文本解释成DOM树;
  • CSS解析器:它的作用是为DOM中的各个元素对象计算出样式信息,为布局提供基础设施;
  • Javascript引擎:使用Javascript代码可以修改网页的内容,也能修改css的信息,javascript引擎能够解释javascript代码,并通过DOM接口和CSS树接口来修改网页内容和样式信息,从而改变渲染的结果;
  • 布局(layout):在DOM创建之后,Webkit需要将其中的元素对象同样式信息结合起来,计算他们的大小位置等布局信息,形成一个能表达这所有信息的内部表示模型;
  • 绘图模块(paint):使用图形库将布局计算后的各个网页的节点绘制成图像结果;

2.渲染过程

浏览器渲染页面的整个过程:浏览器会从上到下解析文档。

  1. 浏览器解析时遇见 HTML 标记,就会调用HTML解析器解析为对应的 token (一个token就是一个标签文本的序列化)并构建 DOM 树(就是一块内存,保存着tokens,建立它们之间的关系)。在生成DOM的最开始阶段(应该是Bytes → characters后),并行发起css、图片、js的请求,无论他们是否在HEAD标签中。

    注意:发起js文件的下载请求(request)并不需要DOM处理到那个script节点;

  2. 遇见 style/link 标记 调用解析器 处理 CSS 标记并构建 CSS样式树;

  3. 遇见 script 标记 调用 javascript解析器处理script标记,绑定事件、修改DOM树/CSS树等;

  4. 将 DOM树 与 CSS树 合并成一棵渲染树(Render Tree)。

  5. 布局(Layout):根据渲染树中各节点的样式和依赖关系,计算出每个节点在屏幕中的位置;

  6. 绘图(Painting):按照计算出来的结果:要显示的节点、节点的CSS与位置信息,通过显卡,把内容画到屏幕上;

经过第一次Painting之后DOMCSSOMRender Tree都可能会被多次更新,比如JS修改了DOM或者CSS属性时,LayoutPainting就会被重复执行。除了DOMCSSOM更新的原因外,图片下载完成后也需要调用Layout 和 Painting来更新网页。

补充:

  • HTML中可能会引入很多的css、js这样的外部资源,这些外部资源在浏览器端是并发加载的。但是浏览器会对同一域名进行并发数量(度)的限制,即单个域名的并发度是有限的;
  • 所以,经常将大部分的资源托管到CDN服务器上,并且设置3~4CDN域名。防止只有一个CDN域名的情况下,达到了浏览器外部资源并发请求数目的上限,导致很多资源无法做到并发请求。所以,应设置多个CDN域名;

3.css阻塞

只有通过link引入的外部css才会产生阻塞:

  • style标签中的样式:

    • html解析器进行解析;
    • 不阻塞浏览器渲染(可能会产生“闪屏现象”);
    • 不阻塞DOM解析;
  • link引入的外部css样式(推荐使用的方式):

    • CSS解析器进行解析;
    • 阻塞浏览器渲染:由于css已经加载完毕,所以整个渲染过程是带样式的,所以这种阻塞可以避免“闪屏现象”;
    • 阻塞其后面的js语句的执行:这个不难理解,js文件中经常会出现DOM操作,操作过程中有可能涉及到css样式的修改。实际上,这些修改往往是依赖于之前引入的css设定的样式的,所以css会阻塞js的执行;
    • 不阻塞DOM的解析;
  • 优化核心理念:尽可能快的提高外部css加载速度:

    • 使用CDN节点进行外部资源加速;
    • css进行压缩(利用打包工具,比如webpackgulp等);
    • 减少http请求数,将多个css文件合并;
    • 优化样式表的代码;

4.js阻塞

  • 阻塞DOM解析:

    原因:浏览器不知道后续脚本的内容,如果先去解析了下面的DOM,而随后的js删除了后面所有的DOM,那么浏览器就做了无用功,浏览器无法预估脚本里面具体做了什么操作,例如像document.write这种操作,索性全部停住,等脚本执行完了,浏览器再继续向下解析DOM;可以通过给script标签添加deferasync属性,异步引入js文件,以此来解决这一问题。

  • 阻塞页面渲染:

    原因:js中也可以给DOM设置样式,浏览器同样等该脚本执行完毕,再继续干活,避免做无用功;

  • 阻塞后续js的执行:

    原因:js是按顺序执行的,这样可以维护依赖关系,例如:必须先引入jQuery再引入bootstrap

  • 不阻塞资源的加载:

    这并不与上面矛盾,因为不可能由于加载一个js文件就把其他资源的加载都阻塞了。针对这种常见的情况,浏览器会通过预加载的方式加载后续的资源;

5.总结

  • css的解析和js的执行是互斥的(互相排斥),css解析的时候js停止执行,js执行的时候css停止解析;

  • 无论css阻塞,还是js阻塞,都不会阻塞浏览器加载外部资源(图片、视频、样式、脚本等);

    因为览器始终处于一种:“先把请求发出去”的工作模式,只要是涉及到网络请求的内容,无论是:图片、样式、脚本,都会先发送请求去获取资源,至于资源到本地之后什么时候用,由浏览器自己协调。显然这种做法效率很高;

  • WebKit 和Firefox 都进行了【预解析】这项优化。在执行js脚本时,浏览器的其他线程会解析文档的其余部分,找出并加载需要通过网络加载的其他资源。通过这种方式,资源可以在并行连接上加载,从而提高总体速度。请注意,预解析器不会修改 DOM 树

四、懒加载和预加载

1.懒加载

图片进入可视区域之后再请求图片资源的方式称为图片懒加载。适用于图片很多,页面很长的业务场景,比如电商;

懒加载的作用:

  • 减少无效资源的加载:

    比如一个网站有十页图片,用户只查看了第一页的图片,这就没必要将十页图片全都加载出来;

  • 并发加载的资源过多会阻塞js的加载,影响网站正常的使用:

    由于浏览器对某一个host name是有并发度上限的,如果图片资源所在的CDN和静态资源所在的CDN是同一个的话,过多图片的并发加载就会阻塞后续js文件的并发加载。

懒加载实现的原理:

监听onscroll事件,判断可视区域位置:

图片的加载是依赖于src路径的,首先可以为所有懒加载的静态资源添加自定义属性字段,用于存储真实的url。比如是图片的话,可以定义data-src属性存储真实的图片地址,src指向loading的图片或占位符。然后当资源进入视口的时候,才将src属性值替换成data-src中存放的真实url

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值