Maoyl's blog Maoyl's blog
首页
  • 前端基础

    • HTML
    • CSS
    • CSS动画
    • JavaScript文章
    • stylus
  • 性能优化

    • 《性能优化》笔记
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《JavaScript设计模式》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架

    • Vue相关
    • React相关
  • 前端监控

    • 前端监控简介
  • 学习笔记

    • 《Vue》笔记
    • 《React》笔记
    • 小程序学习笔记
  • 后端基础

    • Nodejs
  • 学习笔记

    • 数据结构
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网页性能
  • 学习笔记

    • 《Git》学习笔记
    • 《Vim》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

maoyln

日日行,不怕千万里
首页
  • 前端基础

    • HTML
    • CSS
    • CSS动画
    • JavaScript文章
    • stylus
  • 性能优化

    • 《性能优化》笔记
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《JavaScript设计模式》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 前端框架

    • Vue相关
    • React相关
  • 前端监控

    • 前端监控简介
  • 学习笔记

    • 《Vue》笔记
    • 《React》笔记
    • 小程序学习笔记
  • 后端基础

    • Nodejs
  • 学习笔记

    • 数据结构
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网页性能
  • 学习笔记

    • 《Git》学习笔记
    • 《Vim》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 性能优化-requestAnimationFrame
    • 官方简介
    • 带着问题去学习
      • 前端的动画有哪些
      • 这个api较之前做动画的方式优点有哪些
    • requestAnimationFrame的语法规则
    • 为什么定时器会卡,而requestAnimationFrame不会卡
      • 为什么定时器会卡
      • 为何requestAnimationFrame不会卡
  • 《性能优化》笔记
maoyln
2024-08-10
目录

性能优化-requestAnimationFrame

# 官方简介

官网文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame (opens new window)

  • 根据官网简介,我们大致可以知道:requestAnimationFrame这个api主要是用来做动画的。
  • 我们翻译这个英文单词,也能大致明白。request(请求)Animation(动画)Frame(帧)。

# 带着问题去学习

  • 问题1: 前端动画方案有哪些?
  • 问题2: 这个api较之前做动画的方式优点有哪些?

# 前端的动画有哪些

主要分类为css动画和js动画,如下细分:

  • css动画

    • transition过渡动画
    • animation直接动画(搭配@keyframes)
  • js动画

    • setInterval或setTimeout定时器(比如不停地更改dom元素的位置,使其运动起来)
    • canvas动画,搭配js中的定时器去运动起来(canvas只是一个画笔,然后我们通过定时器会使用这个画笔去画画-动画)
    • requestAnimationFrame动画(js动画中的较好方案)

另有svg动画标签,不过工作中这种方式是比较少的,这里不赘述

# 这个api较之前做动画的方式优点有哪些

在工作中,做动画最优的方案无疑是css动画,但是某些特定场景下,css动画无法实现我们所需要的需求,此时,我们就要考虑使用js去做动画了

canvas动画的本质也是定时器动画

使用定时器动画干活,实际上是可以的,但是存在一个最大的问题,就是动画会抖动,体验效果不是非常好。

而,使用requestAnimationFrame去做动画,就不会抖动,体验效果很好

下面一个demo动画(分别是上述两种方式实现dom元素向右平移)给大家看一下,就知道具体的区别。我们先看一下效果图:(红色dom是定时器实现、绿色dom是requestAnimationFrame实现)

demo源码: demo (opens new window)

<html>
  <div class="container">
    <button class="btn" id="btn">👉 let's go!</button>
    <div class="box1" id="box1">定时器动画</div>
    <div class="box2" id="box2">请求动画帧</div>
  </div>
</html>
<script>
  function $(el){
    return document.querySelector(el)
  }
  // 动画思路:不断修改dom元素的left值,使其运动起来(动画)
  let box1 = $('#box1');
  let box2 = $('#box2');

  // setInterval定时器方式
  function setIntervalFn() {
    let timer = null
    console.log(box1, 'box1')
    box1.style.left = '0px'
    timer = setInterval(() => {
      let leftVal = parseInt(box1.style.left)
      if (leftVal >= 720) {
        clearInterval(timer)
      } else {
        box1.style.left = leftVal + 1 + 'px'
      }
    }, 17)
  }

  // requestAnimationFrame请求动画帧方式
  function requestAnimationFrameFn() {
    let timer = null // 可注掉
    console.log(box2, 'box2')

    box2.style.left = '0px'
    function callbackFn() {
      let leftVal = parseInt(box2.style.left)
      if (leftVal >= 720) {
        // 不再继续递归调用即可,就不会继续执行了,下面这个加不加都无所谓,因为影响不到
        // cancelAnimationFrame取消请求动画帧,用的极少,看下,下文中的回到顶部组件
        // 大家会发现并没有使用到这个api(这样写只是和clearInterval做一个对比)
        // 毕竟,正常情况下,requestAnimationFrame会自动停下来
        cancelAnimationFrame(timer) // 可注掉(很少用到)
      } else {
        box2.style.left = leftVal + 1 + 'px'
        requestAnimationFrame(callbackFn)
      }
    }
    requestAnimationFrame(callbackFn)
  }

  $('#btn').onclick = function () {
    console.log('dianj')
    setIntervalFn()
    requestAnimationFrameFn()
  }
</script>
<style>

  .container {
    position: relative;
    height: 400px;
  }
		.box1,
		.box2 {
			position: absolute;
			width: 160px;
			height: 160px;
			line-height: 160px;
			text-align: center;
			color: #fff;
			font-size: 13px;
		}

		.box1 {
			top: 40px;
			background: red;
		}

		.box2 {
			top: 210px;
			background: green;
		}
	</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

例子观察结论

因为笔者的gif录制软件的问题,看着都有点卡,实际上,大家把下方代码复制一份跑起来看的话,会发现定时器动画在微微颤抖,而requestAnimationFrame动画却稳如老狗

# requestAnimationFrame的语法规则

一言以蔽之:requestAnimationFrame和js中的setTimeout定时器函数基本一致,不过setTimeout可以自由设置间隔时间,而requestAnimationFrame的间隔时间是由浏览器自身决定的,大约是17毫秒左右

  1. requestAnimationFrame我们可以在控制台输入window,然后展开查看其身上的属性,就能找到了
  2. 由上图我们可以看到,requestAnimationFrame本质上是一个全局window对象上的一个属性函数,函数是要被执行的,要被调用的。所以我们使时,直接:window.requestAnimationFrame(callBack)即可。
  3. 和定时器一样其接收的参数callback也是一个函数,即下一次重绘之前更新动画帧所调用的函数,即在这个函数体中,我们可以写对应的逻辑代码(和定时器类似)
  4. requestAnimationFrame也有返回值,返回值是一个整数,主要是定时器的身份证标识,可以使用 window.cancelAnimationFrame()来取消回调函数执行,相当于定时器中的clearTimeout()。
  5. 二者也都是只执行一次,想要继续执行,做到类似setInterval的效果,需要写成递归的形式(上述案例中也提到了)

# 为什么定时器会卡,而requestAnimationFrame不会卡

# 为什么定时器会卡

  • 我们在手机或者电脑显示屏上看东西时,显示屏会默默的不停地干活(刷新画面)
  • 这个刷新值得是每秒钟刷新次数,普通显示器的刷新率约为60Hz(每秒刷新60次),高档的有75Hz、90Hz、120Hz、144Hz等等
  • 刷新率次数越高,显示器显示的图像越清晰、越流畅、越丝滑
  • 不刷新就是静态的画面,刷新比较低就是卡了,PPT的感觉
  • 动画想要丝滑流畅,需要卡住时间点进行代码操作(代码语句赋值、浏览器重绘)
  • 所以只需要每隔1000毫秒的60分之一(60HZ)即约为17毫秒,进行一次动画操作即可
  • 只要卡住这个17毫秒,每隔17毫秒进行操作,就能确保动画丝滑
  • 但是定时器的回调函数,会受到js的事件队列宏任务、微任务影响,可能设定的是17毫秒执行一次,但是实际上这次是17毫秒、下次21毫秒、再下次13毫秒执行,所以并不是严格的卡住了这个60HZ的时间
  • 没有在合适的时间点操作,就会出现:类似这样的情况:变、不变、不变、变、不变...
  • 于是就出现了,绘制不及时的情况,就会有抖动的出现(以上述案例,位置和时间没有线性对应更新变化导致看起来抖动)

# 为何requestAnimationFrame不会卡

关键点

  • requestAnimationFrame能够做到,精准严格的卡住显示器刷新的时间,比如普通显示器60HZ它会自动对应17ms执行一次,比如高级显示器120HZ,它会自动对应9ms执行一次。
  • 当然requestAnimationFrame只会执行一次,想要使其多次执行,要写成递归的形式。上述案例也给出了递归写法
  • 这就是requestAnimationFrame的好处。
  • 上述内容验证了:一项新技术新的技术方案的提出,一定是为了解决相关的问题的。
  • window.requestAnimationFrame这个api就是解决了定时器不精准的问题的。
编辑 (opens new window)
#性能优化
上次更新: 2025/04/18, 01:42:12
最近更新
01
GSAP动画库——如何高效写动画
04-17
02
自适应方案PxToRem
09-10
03
js如何实现当文本内容过长时,中间显示省略号,两端正常展示
07-21
更多文章>
Theme by Vdoing | Copyright © 2019-2025 备案号:京ICP备19058102号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式