使用 requestAnimationFrame 提升 web 性能

简介: 使用 requestAnimationFrame 提升 web 性能

requestAnimationFrame 与延时执行函数 setTimeout 类似,但不用设置时间,即可将操作延迟至下一次网页重绘时执行。

requestAnimationFrame 的用法

延迟到下一帧执行

requestAnimationFrame(回调函数)

功能:将回调函数,延迟到下一帧(下一次网页重绘)前执行。

每一帧都执行

在回调函数内再次调用 requestAnimationFrame()

requestAnimationFrame(function update() {
  console.log("执行了更新!");
  // requestAnimationFrame 的回调函数默认只会被调用一次,如果希望每帧都执行,则每帧都需要调用
  requestAnimationFrame(update);
});

取消执行

requestAnimationFrame(回调函数) 会返回一个整数(定时器的编号),将其传给cancelAnimationFrame(定时器的编号) 可取消回调函数的执行,如:

// 定义定时器
let timer1 = requestAnimationFrame(回调函数)
// 取消定时器
cancelAnimationFrame(timer1)

requestAnimationFrame 的常见应用场景

提升 web 性能

使用 requestAnimationFrame 替换 setTimeout 和 setInterva 可提升web性能。

setTimeout 和 setInterva 实现动画的缺点

  • 时间不精确,通常实际执行时间都要比其设定的时间晚一些。
  • 实现的动画在某些低端机上会出现卡顿、抖动的现象。(不同设备的屏幕刷新频率不同,而 setTimeout 和 setInterva 只能设置一个固定的时间间隔,这个时间和屏幕的刷新时间不同时,就会出现掉帧,而导致页面卡顿、抖动)

requestAnimationFrame 实现动画的优势

requestAnimationFrame 采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

全局监听浏览器滚动事件

// 全局监听浏览器滚动事件
window.onscroll = function () {
  requestAnimationFrame(function scroll() {
    console.log("页面滚动了");
  });
};

平滑滚动

<button onclick="scrollToTop()">回到顶部</button>
 
function scrollToTop() {
    const c = document.documentElement.scrollTop || document.body.scrollTop;
    if (c > 0) {
        window.requestAnimationFrame(scrollToTop);
        window.scrollTo(0, c - c / 8);
    }
}

大量数据的渲染

比如十万条数据的渲染,使用 requestAnimationFrame 分页加载。

//需要插入的容器
let ul = document.getElementById('container')
// 插入十万条数据
let total = 100000
// 一次插入 20 条
let once = 20
//总页数
let page = total / once
//每条记录的索引
let index = 0
//循环加载数据
function loop(curTotal, curIndex) {
  if (curTotal <= 0) {
    return false
  }
  //每页多少条
  let pageCount = Math.min(curTotal, once)
  window.requestAnimationFrame(function () {
    for (let i = 0; i < pageCount; i++) {
      let li = document.createElement('li')
      li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
      ul.appendChild(li)
    }
    loop(curTotal - pageCount, curIndex + pageCount)
  })
}
loop(total, index)

使用 setTimeout 实现的写法如下:

//需要插入的容器
let ul = document.getElementById('container')
// 插入十万条数据
let total = 100000
// 一次插入 20 条
let once = 20
//总页数
let page = total / once
//每条记录的索引
let index = 0
//循环加载数据
function loop(curTotal, curIndex) { 
  if (curTotal <= 0) {  
    return false 
  }  
  //每页多少条
  let pageCount = Math.min(curTotal, once) 
  setTimeout(() => {  
    for (let i = 0; i < pageCount; i++) { 
      let li = document.createElement('li')    
      li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)    
      ul.appendChild(li)  
    }  
    loop(curTotal - pageCount, curIndex + pageCount) 
  }, 0)
}
loop(total, index)

监控页面的卡顿

比如连续出现 3 个低于 20 的 FPS 即可认为网页存在卡顿。

var lastTime = performance.now()
var frame = 0
var lastFameTime = performance.now()
var loop = function (time) {
  var now = performance.now()
  var fs = now - lastFameTime
  lastFameTime = now
  var fps = Math.round(1000 / fs)
  frame++
  if (now > 1000 + lastTime) {
    var fps = Math.round((frame * 1000) / (now - lastTime))
    frame = 0
    lastTime = now
  }
  window.requestAnimationFrame(loop)
}

requestAnimationFrame 的优点

  • requestAnimationFrame 会把每一帧中所有的DOM操作集中起来,在一次重绘/回流中完成。
重绘:当某个元素颜色样式发生更改时(如背景颜色、文字颜色),页面也需要更新,浏览器需要重新绘制元素,称为重绘(repaint)。


回流:当页面上的某一个元素的大小或者位置发生更改时,都会影响到与它相邻元素的状况,甚至整个页面的元素状态(位置、元素大小)都需要重新计算和更新。这种操作称为回流(reflow)或者布局(layout)。一个页面至少会有一次回流,就是在页面初始化时。


requestAnimationFrame 重绘/回流的时间间隔紧紧跟随浏览器的刷新频率。充分利用了显示器的刷新机制,比较节省系统资源(显示器有固定的刷新频率60Hz/75Hz,即每秒最多重绘60次或75次,requestAnimationFrame的执行紧跟着系统的绘制频率走,便能保证回调函数在屏幕每一次的绘制间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题)。

对隐藏或不可见的元素,requestAnimationFrame不会进行重绘/回流,这意味着更少的CPU、GPU和内存使用量。

当页面被隐藏或最小化时,requestAnimationFrame会停止渲染(setTimeout 和setInterval 仍然在后台执行动画任务),当页面被激活时,动画会从上次停留的地方继续执行,有效节省了CPU、GPU和电力开销。

requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用

requestAnimationFrame 的缺点

  • requestAnimationFrame 存在兼容性问题,在不支持的浏览器(如 IE9),需添加兼容代码
  • requestAnimationFrame 使用的主线程,若主线程非常繁忙,requestAnimationFrame的动画效果会大打折扣。

兼容写法

对不支持 requestAnimationFrame 的浏览器(如 IE9),需在代码前添加以下兼容代码:

if(!window.requestAnimationFrame){
    var lastTime = 0;
    window.requestAnimationFrame = function(callback){
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0,16.7-(currTime - lastTime));
        var id  = window.setTimeout(function(){
            callback(currTime + timeToCall);
        },timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    }
}

目录
相关文章
|
2月前
|
缓存 数据库 索引
如何优化Python Web应用的性能,包括静态资源加载、缓存策略等?
```markdown 提升Python Web应用性能的关键点:压缩合并静态资源,使用CDN,设置缓存头;应用和HTTP缓存,ETag配合If-None-Match;优化数据库索引和查询,利用数据库缓存;性能分析优化代码,避免冗余计算,使用异步处理;选择合适Web服务器并调整参数;部署负载均衡器进行横向扩展。每一步都影响整体性能,需按需调整。 ```
26 4
|
6天前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
23 0
|
2月前
|
存储 缓存 前端开发
揭秘Web缓存:提升网站性能与用户体验
揭秘Web缓存:提升网站性能与用户体验
|
10天前
|
SQL 缓存 PHP
PHP 与数据库优化:提升Web应用性能的关键
在Web开发中,PHP作为一种流行的服务器端脚本语言,与数据库密切相关。本文探讨了如何通过PHP与数据库优化来提升Web应用的性能和响应速度。从数据库查询优化、索引的设计到PHP代码编写的最佳实践,我们将深入探讨每个方面如何影响应用的效率和用户体验。
|
13天前
|
缓存 负载均衡 安全
Servlet与JSP在Java Web应用中的性能调优策略
【6月更文挑战第23天】在Java Web中,Servlet和JSP调优至关重要,以应对高并发和复杂业务带来的性能挑战。优化包括Servlet复用、线程安全、数据库连接池,以及JSP的编译优化、使用JSTL、页面缓存和静态内容分离。全局优化涉及负载均衡、异步处理和缓存策略。通过这些实践,开发者能提升应用响应速度和吞吐量,确保高负载下的稳定运行。
|
24天前
|
机器学习/深度学习 人工智能 前端开发
WebAssembly:浏览器中的新语言,引领Web性能革命
【6月更文挑战第12天】WebAssembly,简称Wasm,是浏览器中的新语言,旨在带来近乎原生的性能,引领Web性能革命。它具有高效、可移植、安全和多语言支持的特点,适用于游戏开发、图形处理、计算机视觉等领域。随着浏览器支持增强,Wasm将在跨平台应用、AI、机器学习、云计算和边缘计算中发挥更大作用,推动Web应用的发展。
|
2天前
|
缓存 前端开发 JavaScript
web 性能提升(将持续更新……)
web 性能提升(将持续更新……)
9 0
|
8天前
|
监控 Python 缓存
缓存系统提升Web应用性能
【6月更文挑战第22天】
16 0
|
29天前
|
Web App开发 JavaScript 前端开发
Web 页面性能衡量指标-以用户为中心的性能指标
Web 页面性能衡量指标-以用户为中心的性能指标 以用户为中心的性能指标是理解和改进站点体验的关键点 一、以用户为中心的性能指标 1. 指标是用来干啥的? 指标是用来衡量性能和用户体验的 2. 指标类型 • 感知加载速度:网页可以多快地加载网页中的所有视觉元素并将其渲染到屏幕上 • 加载响应速度:页面加载和执行组件快速响应用户互动所需的 JavaScript 代码的速度 • 运行时响应速度:网页在加载后对用户互动的响应速度 • 视觉稳定性:页面上的元素是否会以用户意想不到的方式发生偏移,是否可能会干扰用户的互动? • 流畅性:过渡和动画是否以一致的帧速率渲染,并在一种状态之间流畅地流动
31 1
|
29天前
|
Rust JavaScript 前端开发
WebAssembly初探:提升Web应用性能的关键
WebAssembly(WASM)是一种低级的二进制格式,它允许开发者使用C、C++、Rust等语言编写的代码在Web浏览器中运行,从而实现接近原生的性能。WASM的目标是成为Web平台的一个标准组成部分,提供一个安全、高效的环境来运行高性能的应用程序。
19 0