面试中经常会被问到js性能的一些问题:
比如:最直接的就是js怎么进行优化;还有就是js怎么处理大批量数据;用户交互卡顿怎么处理;等等
下面总结了一些方法,有问题请 ✋^ _ ^
由于JS是一种解释型语言,执行速度要比编译型语言慢得多。( Chrome将JS编译成本地代码的浏览器,其它浏览器也陆续实现了JS的编译过程。但是,即使到了编译执行JS的新阶段,仍然会存在低效率的代码。)
- 加载资源
1)阻塞式脚本:合并文件(减少http请求),将script标签放在body尾部(减少页面css,html的下载阻塞,减少界面的空白时间(避免浏览器在解析到script标签之前,不会渲染页面的任何部分)
目前流行的打包,合并文件的构建工具,如webpack,gulp等
2)无阻塞式脚本:延迟脚本和动态脚本均不阻塞,即下载过程不阻塞其他进程
延迟脚本:
defer和async属性:都是并行下载,下载过程不阻塞,区别在于执行时机,async是下载完成后立即执行;defer是等页面加载完成后再执行。defer仅当src属性声明时才生效(HTML5的规范)
动态脚本:
动态添加script标签,返回的代码通常会立刻执行,所以,为了确保脚本下载完成且准备就绪后才执行,须侦听load事件。将script添加到head中比添加到body中更保险。
在vue中,需要preload
资源
在vue.config.js中设置
chainWebpack: (config) => {
config.plugins.delete('prefetch')
config.plugin('preload').tap((options) => {
options[0].include = 'allChunks'
return options
})
}
- 代码优化
1)作用域
访问当前作用域之外的变量时间会增加,所以 访问全局变量总是比访问局部变量要慢,因为需要遍历作用域链。只要能减少花费在作用域链上的时间,就能增加脚本的整体性能。
// 通过创建一个指向document的局部变量,就可以通过限制一次全局查找来改进此函数的性能。
function updateUI() {
var doc = document,
imgs = doc.getElementByTagName("img");
for(var i = 0, len = imgs.length; i < len; i++) {
imgs[i].title = doc.title + " image " + i;
}
}
2) 减少DOM操作
DOM操作应该是脚本中最耗性能的一类操作,例如增加、修改、删除 元素或者对 DOM集合进行操作。如果脚本中包含了大量的 DOM操作则需要注意
- 限制使用JavaScript来修饰网页布局,把针对访问元素的引用缓存起来。有时,当你的网站依赖大量的DOM改动时,就应该考虑限制你的标记。这
- DOM操作还需要考虑浏览器的 Reflow和Repaint ,因为这些都是需要消耗资源的
- 网络请求
1)减少http请求
一个完整的请求都需要经过 DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个 “漫长” 而复杂的过程。时间成本就是用户需要看到或者 “感受” 到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。另外,由于浏览器进行并发请求的请求数是有上限的,因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给用户造成站点速度慢这样一个印象,即使可能用户能看到的第一屏的资源都已经请求完了,但是浏览器的进度条会一直存在。- 合理设置 HTTP缓存
强缓存:不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的network选项中可以看到该请求返回200的状态码,并且size显示from disk cache或from memory cache;
相关的header:
Expires :response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。它的值为一个绝对时间的GMT格式的时间字符串, 比如Expires:Thu,21 Jan 2018 23:39:02 GMT
Cache-Control :这是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示。当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。比如Cache-Control:max-age=300
关于 HTTP缓存的具体设置和原理此处就不再详述了,有兴趣的可以参考下列文章:👇
[HTTP1.1协议中关于缓存策略的描述] (https://link.zhihu.com/?target=http%3A//www.w3.org/Protocols/rfc2616/rfc2616-sec13.html%2520/t%2520_blank)
[Fiddler HTTP Performance中关于缓存的介绍] (https://link.zhihu.com/?target=http%3A//msdn.microsoft.com/en-us/library/bb250442%28VS.85%29.aspx%2520/t%2520_blank)
协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;另外协商缓存需要与cache-control共同使用。
相关的header:
①Last-Modified和If-Modified-Since:当第一次请求资源时,服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在实体首部上一起返回给客户端。
Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT
客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间是一致的,则说明该资源没有被修改过,直接返回304状态码,内容为空,这样就节省了传输数据量 。如果两个时间不一致,则服务器会发回该资源并返回200状态码,和第一次请求时类似。这样保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。一个304响应比一个静态资源通常小得多,这样就节省了网络带宽。
页面缓存的大致过程
用户行为对浏览器缓存的影响
1.地址栏访问,链接跳转是正常用户行为,将会触发浏览器缓存机制;
2.F5刷新,浏览器会设置max-age=0,跳过强缓存判断,会进行协商缓存判断;
3.ctrl+F5刷新,跳过强缓存和协商缓存,直接从服务器拉取资源。
-
资源合并与压缩
尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image 都可以用相应的工具进行压缩,压缩后往往能省下不少空间。 -
CSS Sprites
合并 CSS图片,减少请求数的又一个好办法。 -
Lazy Load Images
这条策略实际上并不一定能减少 HTTP请求数,但是却能在某些条件下或者页面刚加载时减少 HTTP请求数。对于图片而言,在页面刚加载的时候可以只加载第一屏,当用户继续往后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。 -
接口请求回来的资源可以利用
oss
进行裁剪,大小能节省一半
比如:
<img :src="articleInfo.cover + '?x-oss-process=image/resize,m_fill,h_380,w_680'" alt="">
具体参数参考:https://www.alibabacloud.com/help/zh/doc-detail/44688.htm
-
网络资源(DNS预解析)
资源预加载是另一个性能优化技术,我们可以使用该技术来预先告知浏览器某些资源可能在将来会被使用到。通过 DNS 预解析来告诉浏览器未来我们可能从某个特定的 URL 获取资源,当浏览器真正使用到该域中的某个资源时就可以尽快地完成 DNS 解析。例如,我们将来可从 example.com 获取图片或音频资源,那么可以在文档顶部的 <head> 标签中加入以下内容:
<link rel="dns-prefetch" href="//example.com">
当我们从该 URL 请求一个资源时,就不再需要等待 DNS 的解析过程。该技术对使用第三方资源特别有用。通过简单的一行代码就可以告知那些兼容的浏览器进行 DNS 预解析,这意味着当浏览器真正请求该域中的某个资源时,DNS 的解析就已经完成了,从而节省了宝贵的时间。
另外需要注意的是,浏览器会对a标签的href自动启用DNS Prefetching,所以a标签里包含的域名不需要在head中手动设置link。但是在HTTPS下不起作用,需要meta来强制开启功能。这个限制的原因是防止窃听者根据DNS Prefetching推断显示在HTTPS页面中超链接的主机名。下面这句话作用是强制打开a标签域名解析
<meta http-equiv="x-dns-prefetch-control" content="on"/>
(#已完结#)🤔
网友评论