H5新Api | requestIdleCallback - requestAnimationFram

news2024/9/23 19:25:22

文章目录

  • 浏览器渲染机制
    • 事件循环机制
      • 宏队列与微队列
      • 浏览器中事件循环流程
    • requestAnimationFrame(rAF)
      • requestAnimationFrame API
    • requestIdleCallback
      • requestIdleCallback API
      • 任务拆分
        • requestIdleCallback的使用场景

浏览器渲染机制

  • 每一轮 Event Loop 都会伴随着渲染吗?
  • requestAnimationFrame 在哪个阶段执行,在渲染前还是后?在 microTask 的前还是后?
    requestAnimationFrame在重新渲染屏幕之前执行
  • requestIdleCallback 在哪个阶段执行?如何去执行?在渲染前还是后?
    requestIdleCallback在渲染屏幕之后执行,并且是否有空执行要看浏览器的调度

事件循环机制

作用:事件循环机制的作用是协调事件、用户交互、脚本、渲染及网络任务等。

宏队列与微队列

一个事件循环有一个或多个宏队列,有一个微队列

一个宏队列在数据结构上是一个集合(叫做任务队列),事件循环处理模型会从选定的任务队列中获取一个可运行任务。微队列是FIFO先进先出队列。

  • 宏任务
    • setTimeout、setInterval
    • setImmediate(node 独有)
    • DOM事件、Ajax事件
    • 用户交互、用户操作事件
    • script(整体代码)
    • indexDB操作
  • 微任务
    • process.nextTick
    • Promise一些方法,如.then
    • Async/Await(实际就是promise)
    • MutationObserver(html5新特性)

浏览器中事件循环流程

在这里插入图片描述

  • 同步任务和异步任务进入不同的执行环境,同步任务放入执行栈中,异步任务放入任务队列中。
  1. 先执行同步代码
  2. 检查微任务队列,执行并清空微任务队列,如果在微任务的执行中又加入了新的微任务,也会在这一步一起执行。
  3. 进入更新渲染阶段,判断是否需要渲染(根据屏幕刷新率、页面性能等)。并不是每轮事件循环都会执行浏览器渲染
  4. 没有就开启下一轮循环,取出一个宏任务执行。一个宏任务执行完毕后就清空微队列,然后见检查需不需要。循环这个过程

DOM的修改不会立刻导致渲染,渲染线程和Javascript线程是互斥的,必须等待Javascript的这次调度执行完或线程挂起了,才能执行渲染。
这次调度可以看成是一轮事件循环完,一次事件循环=宏任务(第一次是同步代码)+微任务
在这里插入图片描述

requestAnimationFrame(rAF)

是什么

requestAnimationFrame是H5新增的API类似于setTimeout ,告诉浏览器在重新渲染屏幕之前执行。主要用途是按帧对网页进行重绘。

rAF是官方推荐的用来做一些流畅动画所应该使用的 API,做动画不可避免的会去更改 DOM,而如果在渲染之后再去更改 DOM,那就只能等到下一轮渲染机会的时候才能去绘制出来了

优势
调用时机:在重新渲染前调用。
requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机。保证回调函数在屏幕每一次刷新间隔中只执行一次,避免丢帧

如果浏览器不渲染,是不是就不会调用requestAnimationFrame? 如果requestAnimationFrame做太多事情,会导致降频,比如1s刷新60次变成1s刷新30次。

requestAnimationFrame API

基本语法:requestAnimationFrame (callback)
返回值:回调函数列表中的唯一值,可以使用cancelAnimationFrame传入请求ID取消回调函数。

说明

  1. requestAnimationFrame不管理回调函数,意思是多次调用带有同一回调函数的 requestAnimationFrame,会导致回调在同一帧中执行多次。
    由rAF的返回值是回调函数列表中的唯一值,可以理解为即使是同一回调函数,但是在回调函数列表中的值都是不一样的。
    所以配合cancelAnimationFrame使用。
  2. requestAnimationFrame() 运行在后台标签页或者隐藏的<iframe> 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。

requestIdleCallback

对于人眼来说,当每秒切换60张图片时,就会认为是连贯的。所以主流的显示器是60hz的(1s刷新60次),那么每16.7ms需要刷新一次,浏览器会自动适配这个频率,这时对应前端页面就是每16.7ms需要渲染一次。
在这里插入图片描述

页面每隔16.7ms才会渲染一次,那么在两次渲染的中间时间,就是浏览器的空闲时间,在这段空闲时间执行的任务,是不会阻塞到页面渲染的流畅性的。

如果在某一帧区间内执行过多的任务会导致下一帧一直没办法渲染,页面看起来就被卡住。

对大量任务的计算首先考虑Web Worker 使其不占用主线程,如果需要操作DOM,可以考虑任务拆分。

在这里插入图片描述
图中一帧包括了用户的交互, JavaScript 脚本执行; 以及requestAnimationFrame(rAF)的调用, 布局计算以及页面重绘等。如果某一帧里执行的任务不多, 在不到 16.66ms内就完成了上述任务, 那么这一帧就会有一定空闲时间来执行requestIdleCallback的回调。会在layout/paint 之前调用。

回流也叫重排(layout),当 DOM 的变化影响了元素的几何信息(位置、尺寸大小等),浏览器需要重新计算元素的几何属性,将其安放在界面的正确位置,这个过程叫做回流。
当一个元素的外观发生变化,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘(paint)。

requestIdleCallback API

基本语法:requestIdleCallback(callback,options)

  • callback被调用时,回接受一个参数 deadlinedeadline是一个对象,对象上有两个属性
    • timeRemaining属性是一个函数,函数的返回值表示当前空闲时间还剩下多少时间
    • didTimeoutdidTimeout属性是一个布尔值,如果didTimeouttrue,那么表示本次callback的执行是因为超时的原因
  • options是一个对象,可以用来配置超时时间。如果指定了timeout,但是浏览器没有在timeout指定的时间内,执行callback。在下次空闲时间时,callback会强制执行。并且callback的参数,deadline.didTimeout=true, deadline.timeRemaining()返回0。

空闲时间
在空闲期间,callback的执行顺序是以FIFO(先进先出)的顺序。但是如果在空闲时间内依次执行callback时,有一个callback的执行时间,已经将空闲时间用完了,剩下的callback将会在下一次的空闲时间执行。
在这里插入图片描述

const startTask = (deadline) {
    // 如果 `task` 花费的时间是20ms
    // 超过了当前空闲时间的剩余毫秒数,我们等到下一次空闲时间执行task
    if (deadline.timeRemaining() <= 20) {
        // 将任务带到下一个空闲时间周期内
        // 添加到下一个空闲时间周期callback列表的末尾
        requestIdleCallback(startTask)
    } else {
        // 执行任务
        task()
    }
}

当网页处于不可见的状态时(比如切换到其他的tag),空闲时间将会每10s, 触发一次空闲期。

任务拆分

将批量的任务进行拆分,保证这些任务只在空闲时间执行。每次执行下一个任务时,先检查当前页面是否该渲染下一帧了,如果是则让出线程,进行页面渲染。
requestIdleCallback是浏览器提供给我们用来判断这个时间的api,它会在浏览器空闲的时候来执行其回调函数,如果指定了超时时间,会在超时后的下一帧强制执行。

const id = window.requestIdleCallback((deadline) => {
  // 当前帧剩余时间大于0,或任务已超时
  if(deadline.timeRemaining() > 0 || deadline.didTimeout) {
      // do something
      console.log(1)
  }
}, { timeout: 2000 }) // 指定超时时间

// window.cancelIdleCallback(id) 与定时器类似,支持取消

requestIdleCallback在Event Loop的执行时机如下图所示,蓝色区域代表一帧内的渲染任务,当这些任务执行完后,剩余的时间被认为是空闲时间。
在这里插入图片描述
使用案例

// class中的一个方法
idleDownload(){
	// 先取消之前的
	cancelIdleCallback(this.ridId); // ridId是class中的属性,存放一个requestIdleCallback的id
	const { tasks } = this // tasks为总任务数
	let index = 0; // 任务索引
	const ridOption = {timeout:2000}; // 指定超时时间,会在超时后的下一帧强制执行。
	// 当前帧空闲时执行的回调函数
	const handler = (idleDeadline) => {
		const {timeRemaining} = idleDeadline; // 获取空闲时间
		while(timeRemaining()>0 && index<tasks.length ){
			// 在空闲时间执行任务
			index ++;
		}
		// 判断任务是否下载完成
		if(index< tasks.length){ // 不空闲了,但是任务还没有执行完毕
			this.ridId = requestIdleCallback(handler, ridOption); // 继续等待下次空闲时下载
		}else{ 
		// 已经下载完毕
		}
	}
	this.ridId =  requestIdleCallback(handler, ridOption); 
}
requestIdleCallback的使用场景

适用场景

  1. 预加载
  2. 检测卡顿
    如果requestIdleCallback长时间内没能得到执行,说明一直没有空闲时间,很有可能就是发生了卡顿,从而可以打点上报。它比较适用于行为卡顿,举个例子:点击某个按钮并同时添加requestIdleCallback 回调,如果点击后的一段时间内这个回调没有得到执行,很大概率是这个点击操作造成了卡顿。
  3. 拆分耗时任务

不适用场景

  • 更新DOM操作
    requestIdleCallback回调执行之前, 样式变更以及布局计算等都已经完成。如果在callback中修改DOM, 之前所作的布局计算都会失效。 并且如果下一帧里有获取布局相关的操作, 浏览器就需要强制进行重排, 极大的影响性能。 另外由于修改 DOM 的时间是不可预测的, 因此容易超过当前帧空闲的阈值.
  • promise 的回调(resolve/reject)属于优先级较高任务,在一帧的过程中如果产生了微任务会执行微任务。所以会在 requestIdleCallback 回调结束后立即执行,可能会给这一帧带来超时的风险。
// console
// 空闲时间1
// 等待了1000ms
// 空闲时间2
// Promise 会在空闲时间1接受后立即执行,即使没有空闲时间了也是如此。拖延了进入下一帧的时间

requestIdleCallback(() => {
    console.log('空闲时间1')
    Promise.resolve().then(() => {
        sleep(1000)
        console.log('等待了1000ms')
    })
})

requestIdleCallback(() => {
    console.log('空闲时间2')
})

参考文章:
批量任务导致页面卡死?试试requestIdleCallback对任务进行拆分
详解 requestIdleCallback
requestAnimationFrame 执行机制探索

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1141284.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣:142. 环形链表 II(Python3)

题目&#xff1a; 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评…

命令行参数、环境变量

我们在使用C语言的时候&#xff0c;经常的写法是int main(){//函数体}。 而且我们也知道它也只是一个函数&#xff0c;当一个进程启动的时候&#xff0c;会有专门的函数来调用这个函数。 那他有没有函数参数呢&#xff1f;其实也是有的&#xff0c;我们今天&#xff0c;就来认识…

常用的网络攻击手段

前言&#xff1a;本文旨在介绍目前常用的网络攻击手段&#xff0c;分享交流技术经验 目前常用的网络攻击手段 社会工程学攻击物理攻击暴力攻击利用Unicode漏洞攻击利用缓冲区溢出漏洞进行攻击等技术 社会工程学攻击 社会工程学 根据百度百科定义&#xff1a; 社会工…

2023/10/27 JAVA学习

tab键可以对文件名进行补全 想切到其他盘的某个文件,必须先使用切盘命令 在当前文件目录输入cmd,可直接打开命令行窗口,并且处于当前文件目录 运行java文件,只用文件名不需要后缀 记得勾选文件扩展名 直接这样执行不会出现class文件,因为在底层临时生成了一个,不会长久的出现

NX二次开发后处理中保存tcl变量值到文本

直接上代码&#xff1a; static bool GetTclValue(UF_MOM_id_t mom_id, char *szName, char *szInfo, std::string &stValue,bool bShowValue /* false*/) {UF_MOM_ask_string(mom_id, szName, (const char **)&szInfo);if (szInfo){stValue szInfo;if (bShowValue){…

ArrayList的线程安全类CopyOnWriteArrayList

目录 一、CopyOnWriteArrayList简介二、CopyOnWriteArrayList的优缺点1、优点2、缺点 三、CopyOnWriteArrayList使用场景1、数据库缓存2、消息队列3、数据统计和分析 四、使用CopyOnWriteArrayList时需要注意哪些问题&#xff1f;1、内存占用问题2、数据一致性问题3、线程安全4…

Milvus 入门教程

文章目录 下载docker-compose配置文件安装 docker安装docker-compose直接下载release版本手动安装使用pip 命令自动安装 通过 docker-compose 启动容器连接 Milvus停止 milvus删除milvus的数据 下载docker-compose配置文件 先安装wget命令 yum install wget下载配置文件&…

C++之C++11字符串字面量后缀总结(二百四十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

如何高效自学(黑客技术)方法——网络安全

如果你想自学网络安全&#xff0c;首先你必须了解什么是网络安全&#xff01;&#xff0c;什么是黑客&#xff01;&#xff01; 1.无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面性&#xff0c;例如 Web 安全技术&#xff0c;既有 Web 渗透2.也有 Web 防…

2023版 STM32实战12 IIC总线读写AT24C02

IIC简述 一个多主从的串行总线&#xff0c;又叫I2C&#xff0c;是由飞利浦公司发明的通讯总线 IIC特点 -1- 串行(逐bit传输) -2- 同步(共用时钟线) -3- 半双工(收发不同进行) -4- 总线上的任何设备都可以是主机 开发使用习惯和理解 -1- 通过地址寻址 -2- 数据线的…

Linux权限及Xshell运行原理

目录 1.Linux中的用户 1.1 用户分类 1.2 用户切换 2.权限的概念 2.1 权限概念以及表示 2.2 文件属性以及类型 2.2.1 文件属性 2.2.2 文件类型 2.3 Linux下的角色 3.权限的修改 3.1 chmod 3.2 chown 3.3 chgrp 4.目录权限 5.权限掩码 5.1 默认权限 5.2 起始权限…

省时省力!掌握简单快捷的关机命令,轻松实现电脑的自由开关机

本文介绍了为电脑设置特定的自动关机时间的四种方法。我们还包括如何停止计划关机的信息。 如何用命令提示符安排计算机关机 按照以下步骤使用命令提示符进行一次性关闭。 1、在Windows搜索框中,键入CMD。 2、点击Enter。 3、在命令提示符窗口中,键入shutdown -s -t 和所…

matlab simulink 四旋翼跟拍无人机仿真

1、内容简介 略 7-可以交流、咨询、答疑 2、内容说明 四旋翼跟拍无人机仿真 四旋翼、无人机 需求分析 背景介绍 无人飞行机器人&#xff0c;是无人驾驶且具有一定智能的空中飞行器。这是一种融合了计算机技术、人工智能技术、传感器技术、自动控制技术、新型材料技术、导航…

基于机器视觉的车道线检测 计算机竞赛

文章目录 1 前言2 先上成果3 车道线4 问题抽象(建立模型)5 帧掩码(Frame Mask)6 车道检测的图像预处理7 图像阈值化8 霍夫线变换9 实现车道检测9.1 帧掩码创建9.2 图像预处理9.2.1 图像阈值化9.2.2 霍夫线变换 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分…

HCL模拟器选路实验案例

此选路题目选自职业院校技能竞赛中的一道题比较考验思路&#xff0c;适合于参加新华三杯大赛以及网络专业的同学&#xff0c;当做练习题目进行解题​​​​​​​ 题目 1.S1、S2、R1、R2运行ospf进程100&#xff0c;区域0&#xff0c;R1、R2、R3、R4、R5运行ospf进程200&#…

Linux进阶之旅:从零开始,探索基本指令的神秘力量!

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是尘缘&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f449;点击这里&#xff0c;就可以查看我的主页啦&#xff01;&#x1f447;&#x…

【java学习—九】工厂方法FactoryMethod(6)

文章目录 1. 概念2. 实际的应用 1. 概念 FactoryMethod 模式是设计模式中应用最为广泛的模式&#xff0c;在面向对象的编程中&#xff0c;对象的创建工作非常简单&#xff0c;对象的创建时机却很重要。 FactoryMethod 解决的就是这个问题&#xff0c;它通过面向对象的手法&…

RabbitMQ初入门

1、RabbitMQ是什么 RabbitMQ是“实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理软件&#xff08;亦称面向消息的中间件&#xff09;。RabbitMQ服务器是用Erlang语言编写的&#xff0c;而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均…

23 行为型模式-迭代器模式

1 迭代器模式介绍 迭代器模式是我们学习一个设计时很少用到的、但编码实现时却经常使用到的行为型设计模式。在绝大多数编程语言中&#xff0c;迭代器已经成为一个基础的类库&#xff0c;直接用来遍历集合对象。在平时开发中&#xff0c;我们更多的是直接使用它&#xff0c;很…

C++学习 day--21 地震监测系统实现、内存泄漏检测工具

1、项目需求 地震监测系统主要是利用地震检波器收集到的地壳运动信息&#xff0c;从而预测和确定地震的震中以 及强度。 预测方法 地震检波器每隔固定的时间间隔采样一次预测地震的能量数据&#xff0c;并保存到文件中&#xff0c;地震监测 系统会从文件中读取相应的能量数据&…