跳到主要内容

性能优化

待完善

  • 减少HTTP请求
    • 合并资源文件(CSS, JS, 雪碧图)
    • 压缩资源文件
    • 图片懒加载(借助IntersectionObserver)
    • 合理设置HTTP缓存, CDN缓存
  • 首屏渲染优化
    • 代码分割,路由懒加载
    • 骨架屏
  • 代码优化
    • 不用table (流式布局)
    • 不用with, eval
  • CSS优化
    • CSS3(transform, opacity)硬件加速
    • 频繁操作DOM时,可以先用display: none使其脱离文档流再进行DOM操作
    • 对于复杂的动画效果,可以使用position: absolute使其脱离文档流
  • JS优化
    • 函数防抖,函数节流

Base64

Base64的原理就是使用64个可见字符来表示二进制字节序列。

具体来说,对于一个字节序列,我们会把每三个字节作为一组,然后将这24位比特分为四个小组,每个小组前面加上00。因此原本的24比特变成了32个比特,也就是4个字节,之后再将这些字节分别映射为64个字符。这也是为什么通过Base64编码后的文本会比原先多三分之一。

基于这个特性,Base64存在许多用途。最基本的用途是对纯文本进行编码,以达到一种伪加密的手段,比如JWT就使用了Base64来对数据进行编码。

除此之外,使用Base64可以把图片资源的二进制内容编码成文本,之后再使用<img src="data:img/gif;base64,base64,xxxxxxxx">的形式加载,对于小型图片来说我们可以减少HTTP请求数来实现优化的功能。

图片懒加载

常规方法(使用offsetTop - scrollTop 或者 getBoundingClientRect())

<body>
<div class="blank">
// 很长的元素,使图片开始不在视口里
</div>
<div class="image" data-url="C:/Users/Messiah/Pictures/image.png">
// 想要懒加载的图片
</div>
<script type="text/javascript">
let image = document.querySelector('.image')

window.onscroll = throttle(() => {
// 方法一,使用offsetTop - scrollTop
if (image.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight)
{
let url = image.dataset.url
image.style.backgroundImage = `url(${url})`
}

// 方法二,使用getBoundingClientRect
if (image.getBoundingClientRect().top < document.documentElement.clientHeight) {
let url = image.dataset.url
image.style.backgroundImage = `url(${url})`
}
}, 200)

// 节流函数
function throttle (fn, time) {
let canRun = true
return function () {
if (!canRun) return false
canRun = false
setTimeout(() => {
fn()
canRun = true
}, time)
}
}

</script>
</body>

https://zhuanlan.zhihu.com/p/55311726

offsetParent定义: 一个元素的已定位(position不为static)的父元素, 类似于绝对定位中已经定位的父元素,如果一个元素没有已经定位的父元素,则该元素的offsetParent为body。

此例子中image.offsetTop,image没有已经定位的父元素,则image的offsetParent为body。

如果我们的代码结构如下,

    <body>
<div class="outer">
<div class="blank">

</div>
<div class="image">

</div>
</div>

</body>

滚动条在outer上,我们应该给outer加一个样式

.outer {
position: relative;
}

那么,image.offsetParent就是outer,我们就可以继续使用以下代码来判断图片是否进入视口

image.offsetTop - outer.scrollTop < outer.clientHeight

IntersectionObserver

// 使用IntersectionObserver,十分方便
let io = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return
else {
let el = entry.target
el.style.backgroundImage = `url(${el.dataset.url})`
io.unobserve(el)
}

})
})
io.observe(document.querySelector(".image"))
// <div class="image" data-url="https://xxx.com/1.jpg" ></div>

这个API同样能用来实现无限滚动(Infinity Scroll)

雪碧图

合并HTTP请求,使用background-position来选择使用的图片。

setTimeout/setInterval和requestAnimationFrame

setTimeout/setInterval

setTimeout(fn, n)会在指定的时间n毫秒后,将指定的回调函数fn放进任务队列中,因此并不是n秒后就会执行回调函数。

setTimeout(fn, 0) 即使传参为0ms,最短其实为4 ms。

缺点: 一般显示器刷新频率为60HZ,即16.6ms刷新一次屏幕。setTimeout可能会掉帧。

requestAnimationFrame

function myAnimation() {
// do something
requestAnimationFrame(myAnimation)
}

requestAnimationFrame(myAnimation)

它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次