Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端基础

  • 应用框架

  • 工程能力

  • 应用基础

    • 兼容性

    • 前端安全

    • 国际化

    • 性能优化

      • 如何实现 script 并行异步加载顺序执行
      • yahoo前端优化35军规
      • 前端首屏优化 | 借助客户端能力提升 H5 首屏的 8 个手段
      • 前端优化性能指标
      • 4 种常用的前端性能分析工具
      • 前端性能预算经验
      • 前端图片分层加载详解
      • 基于CDN的前端优化可行性分析
      • 浅谈图片分层加载与懒加载
      • 浅谈 preload 预加载
      • 用 CAP 理论指导 Hybrid App 离线策略优化
      • 长列表

        • rc-virtual-list 源码解析
        • 为什么不用rAF进行滚动节流
          • 前言
          • 背景知识之事件循环
          • 输入事件与滚动事件的执行时机
          • 什么时候滚动需要做节流
          • 结论
          • 拓展阅读
        • 「前端长列表」开源库解析及最佳实践
        • 如何解决长列表的滚动白屏问题
      • 面试官问:如何实现 H5 秒开?
    • 换肤

    • 无障碍

  • 专业领域

  • 业务场景

  • 大前端
  • 应用基础
  • 性能优化
  • 长列表
gahing
2020-01-07
目录

为什么不用rAF进行滚动节流

# 前言

之前写了一篇长列表实现的分享 -- 「前端长列表」开源库解析及最佳实践 (opens new window)

然后面试被问到的最多的问题就是:有没有做节流

当时的回答是没有,但是又说不出一个系统的回答

本文就来说说为什么长列表不需要做节流,以及什么情况下滚动需要做节流

# 背景知识之事件循环

详见HTML规范 (opens new window)

这里只挑与本文相关的讲

在事件循环中定义了很多任务源,比如鼠标键盘等输入操作的用户交互任务源

一次点击操作,其实包含多个输入操作(mousedown,mouseup,click),都添加到相同的任务源队列中,进而产生多轮的事件循环,其表现就是执行相关元素的事件回调(宏任务)

宏任务执行后,后面就是微任务队列和更新渲染阶段

每轮事件循环可能是非常快的,每秒执行事件循环的次数可能大于60次

受硬件刷新率影响,我们只要保证 fps 达到最大硬件刷新率(比如60)即可,因此不需要每轮事件循环都更新渲染

# 输入事件与滚动事件的执行时机

对于输入事件,其执行时机为每轮事件循环的任务执行阶段,这个事件是不受刷新率影响的,每秒的执行次数可能多于60次

为什么谈这个呢,因为这个与滚动事件(scroll)回调的执行时机不一致

按照 HTML 规范,滚动事件回调在 UI Render 阶段的某个步骤中进行,而不是单独的一个任务源

也就是说,滚动事件回调受渲染时机影响,仅执行更新渲染时才执行该回调。

换句话说,该事件自带节流。

举个例子验证下输入事件和更新渲染的执行时机

document.addEventListener("mousemove",function(){
  let start = performance.now()
  console.log("mousemove:",start)
  requestAnimationFrame(function(t){console.log("ui render:",start,t)})
})
// 结果就是可能输出几轮 mousemove 然后执行一次 ui render -- 清空 rAF 回调队列(输出多次 ui render)
/*
mousemove: 4091.025000088848
ui render: 4091.025000088848 4077.594
mousemove: 4098.845000029542
ui render: 4098.845000029542 4094.278
mousemove: 4110.160000040196
mousemove: 4115.5349999899045
ui render: 4110.160000040196 4110.962
ui render: 4115.5349999899045 4110.962
mousemove: 4123.810000019148
mousemove: 4130.160000058822
ui render: 4123.810000019148 4127.719
ui render: 4130.160000058822 4127.719
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

说明更新渲染有一定的间隔,至少是 1/60 的间隔,而输入任务没有此限制

所以,以下代码是没有效果的,因为该回调已经自带节流了

document.addEventListener("scroll",function(e){
  requestAnimationFrame(function(t){
    //执行scroll具体逻辑
  })
})
1
2
3
4
5

# 什么时候滚动需要做节流

利用节流可以减少回调的执行次数,使得固定时间周期内只执行一次

刚才提到,滚动事件自带节流,节流的时间周期是与渲染时机相关

判断是否需要额外的节流的关键是:当前的节流规则,是否大部分回调的执行都能让用户受益

如果是动画效果,实时绘制的界面等,则不需要额外的节流了。

以长列表为例,每次执行滚动回调,会计算新的渲染列表项及滚动偏移位置。如果应用更大时间周期的节流,会出现某一帧出现滚动但界面没有更新的情况,让用户感觉产生卡顿。

而其他比较复杂的业务逻辑,不能在短时间内得到反馈的,则需要额外进行节流

以滚动懒加载图片为例

由于每秒的滚动回调的执行次数可能达到60次,而每次执行都需要去获取当前处于视区的占位图并发起图片请求

而这大部分回调的执行,用户是不能受益的,所以我们可以提高节流的时间周期,比如 500ms 这样

# 结论

滚动事件已自带节流,只有一些特定的业务逻辑才需要额外进行更高时间周期的节流

# 拓展阅读

  1. scroll events: requestAnimationFrame VS requestIdleCallback VS passive event listeners (opens new window)
编辑 (opens new window)
#长列表
上次更新: 2024/09/01, 23:56:56
rc-virtual-list 源码解析
「前端长列表」开源库解析及最佳实践

← rc-virtual-list 源码解析 「前端长列表」开源库解析及最佳实践→

最近更新
01
浅谈代码质量与量化指标
08-27
02
快速理解 JS 装饰器
08-26
03
Vue 项目中的 data-v-xxx 是怎么生成的
09-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式