requestIdleCallback 和 requestAnimationFrame如何使用

1,338 阅读1分钟

requestIdleCallback

原理

将在浏览器的空闲时段内调用的函数排队。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。

使用方式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ric</title>
  <style>
    * {
      width: 100%;
      height: 100%;
      text-align: center;
      margin: 0;
    }
    #div {
      position: absolute;
      height: auto;
      top: 50%;
      margin-top: -50px;
    }
  </style>
</head>
<body>
  <h3 style="display:none;">单击“ESC”退出当前状态</h3>
  <div id="div">请点击当前屏幕,获取ric的相关参数</div>
</body>
<script>
  let idleCallback = null
  let isExit = false
  function ricCB (idleDeadline) {
    // didTimeout表示是否超时
    const didTimeout = idleDeadline.didTimeout ? '超时' : '未超时'
    // timeRemaining()表示当前帧还剩余多少时间(以毫秒计算)
    // 一般一帧的时间是16.6ms,所以timeRemaining()取到的时间是小于这个值
    // 如果为0,表示当前帧已经没有时间去处理回调
    // 若强行调用回调,可能导致丢帧或者卡顿
    const timeRemaining = idleDeadline.timeRemaining()
    // 业务逻辑代码
    document.getElementById('div').innerText = `当前帧的前提下:\n是否超时:${didTimeout}; \n当前帧剩余时间${timeRemaining}ms`
  }
  document.body.onclick = function () {
    window.cancelIdleCallback(idleCallback)
    if (!isExit) {
      idleCallback = window.requestIdleCallback(ricCB)
      document.querySelector('h3').style.display = 'block'
    }
  }
  document.onkeydown = function (event) {
    // ESC 退出当前调用
    if (event.code === 'Escape') {
      isExit = true
    }
  }
</script>
</html>

演示效果

演示结果

requestAnimationFrame

原理

告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行

使用方式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>raf</title>
  <style>
    * {
      width: 100%;
      height: 100%;
      text-align: center;
      margin: 0;
    }
    #div {
      position: fixed;
      height: auto;
      top: 50%;
      margin-top: -50px;
    }
  </style>
</head>
<body>
  <div id="div">页面将在3秒后,显示当前鼠标的实时位置</div>
  <div style="height:100%;"></div>
  <div style="height:300%; padding-right: 100%;"><div id="div1" style="margin-left: 100%;width:100px; height: 100px; background-color: cornflowerblue;"></div></div>
</body>
<script>
  let isExit = false
  let rafId = null
  function rafCB (idleDeadline) {
    if (isExit) return window.cancelAnimationFrame(rafId)
    // 业务逻辑代码
    const dom = document.getElementById('div1')
    const domRect = dom.getBoundingClientRect()
    document.getElementById('div').innerText = `蓝色框所在的位置(请注意滚动条位置):\n距离页面左边: ${domRect.left}; \n距离页面顶部: ${domRect.top}`
    rafId = window.requestAnimationFrame(rafCB)
  }
  setTimeout(() => {
    rafId = window.requestAnimationFrame(rafCB)
  }, 3000)
  document.onkeydown = function (event) {
    // ESC 退出当前调用
    if (event.code === 'Escape') {
      isExit = true
    }
  }
</script>
</html>

演示效果

演示效果