- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
简单理解节流就是节省资源开销,之前说回流是GPU给元素画图之前需要根据布局去计算元素的一些位置属性,例如宽、高、横纵坐标等等,那反复计算这些就是回流。节流又是节省资源开销,不让一些事件函数高频率的反复执行.....其实回流和节流还是有一定关系但也不是特别大.
首先什么是防抖?为什么要防抖?
某天晚上大春和马冬梅决定偷偷FQ去看望受伤的夏洛,在夏洛窗外,冬梅让大春放哨,看见有人过来了就说一声,当冬梅FQ一半的时候,大春刚好看到一个拿三叉戟的黑影出现在电话亭那边,大春很着急,立马告诉冬梅“冬梅啊有人来了要不咱们撤吧,冬梅啊有人来了要不咱们撤吧,冬梅啊有人来了要不咱们撤吧.....”.
好回到正题,防抖之前:大春反复的说“冬梅啊有人来了要不咱们撤吧”,防抖之后:就一句“冬梅啊有人来了要不咱们撤吧”。所以所谓 防抖也就是防止事件没必要的重复触发 .
为什么要防抖,其实这个问题以前自己肯定是遇到这种场景的,只是当时能力还不够来考虑这种性能优化的问题。例如:使用vue时@input事件绑定在input组件上随意输入一个内容他都会触发事件对吧,那我就想要输入完成后再触发嘞(不杠@change), 再例如监听滚动事件 scroll 时会密集的触发对吧,那我就是不想让他密集的触发。还有浏览器窗口大小改变的事件resize、keypress、mousemove等等都是高频事件,他们在触发时会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能.
像 scroll 这种高频事件整体的触发完成之后,再进行事件操作,这才是我想要的。就是所谓的“ 防抖 ”, 其本质就是优化高频执行代码的一种手段 .
什么是节流?为什么要节流?
这时候在墙上的冬梅瞅了瞅原来是个渔夫在那里打电话而已,告诉大春“大春没事儿,他不是保安,真走过来了你再告诉我”,不一会大春又看到那渔夫真过来了,一步两步好像在跳舞边跳边走,于是大春跟着他的节奏,走两步就告诉冬梅“冬梅那渔夫好像过来了”,走两步就告诉冬梅“冬梅那渔夫好像过来了”.......
好回到正题,节流之前:大春反复的说“冬梅那渔夫好像过来了”,节流之后:大春跟着节奏每两步才说。 还有个栗子防抖就像王者的回城,打断了就要重新来,节流是技能冷却,需要等cd时间过了才能继续使用技能。我王者这个栗子感觉不是特别准确,看怎么理解吧.
节流跟防抖差不太多,区别在于防抖是避免事件没必要地大量重复执行,而节流是这种“避免”放松一点,在事件连续触发的时候规定时间间隔每执行一次就好,例如给scroll事件设置防抖那他从开始滚动到最后也就执行一次,而给scroll事件设置节流则是在开始滚动到结束滚动的时间内定时轮番的去执行操作。这就是 节流 .
节流和防抖的区别:
防抖是 多次触发,只执行最后一次。适用于只需要一次触发生效的场景.
节流是 每隔一段时间触发一次操作。适用于多次触发要多次生效的场景.
应用场景:
debounce 。
search搜索联想,用户在不断输入值时,用防抖来节约请求资源.
window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次 。
throttle 。
鼠标不断点击触发,mousedown(单位时间内只触发一次) 。
监听scroll滚动事件,比如是否滑到底部自动加载更多,用throttle来判断 。
。
大致思路:通过定时器(延迟器)实现,第一次触发之后设置好定时器,如果之后再有该事件触发那就把上一次的定时器清理再重新设置定时器,定时时间到则执行目标操作,如此反复.
先看一种比较简单的防抖实现(非立即执行版本),就是需要经过定时器的延迟才会执行.
// 防抖 定时器实现(非立即执行版本)
function debounce(fn, delay = 200) {
let timer = null
return function() {
if(timer){ // 如果设置过了定时器
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments); // 透传 this和参数
timer = null
},delay)
}
}
再看立即执行版本:立即执行的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果.
// 防抖 定时器实现(立即执行版本)
function debounce(fn, delay = 200) {
let timer = null
return function () {
let args = arguments
let now = !timer
timer && clearTimeout(timer) //timer不为null时执行clearTimeout函数
timer = setTimeout(() => {
timer = null
}, delay)
if (now) {
fn.apply(this, args)
} //或者:now && fn.apply(this, args)
}
}
上边调用设置之后,在绑定事件的时候这样使用就好 。
window.onscroll = debounce(lozyLoad,1000); //lozyLoad是想要执行的回调函数
。
节流的简单实现:
// 节流函数(简单版本):第一次触发时不会执行,而是在delay毫秒之后才执行
function throttle(fn, delay = 200) {
let timer = 0
return function () {
if(timer){
return
}
timer = setTimeout(() =>{
fn.apply(this, arguments); // 透传 this和参数
timer = 0
},delay)
}
}
也是节流的简单实现:
//节流函数(时间戳版):触发事件时立即执行,以后每过delay毫秒之后才执行一次,并且最后一次触发事件若不满足要求不会被执行
function throttle(fn ,delay = 200){
let oldtime = Date.now();
return function(){
let context = this;
let args = arguments;
let newtime = Date.now();
if(newtime - oldtime >= delay){
fn.apply(context,args);
oldtime = Date.now();
}
}
}
其实就是将以上两种方式相结合,实现一个更加精准的节流: 第一次会马上执行,最后一次也会执行 。
//节流函数:定时器和时间戳结合版本
function throttle(fn ,delay = 200){
let timer = null;
let starttime = Date.now();
return function(){
let curTime = Date.now();
let remaining = delay -(curTime - starttime);
let context = this ;
let args = arguments;
clearTimeout(timer);
if(remaining <= 0) {
fn.apply(context,args);
starttime = Date.now();
}else{
timer = setTimeout(fn,remaining);
}
}
}
。
可以参考这篇文章对代码有更详细的注释: 链接 。
。
最后此篇关于防抖和节流的文章就讲到这里了,如果你想了解更多关于防抖和节流的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我的 Tableview 有 N 个部分,其中 0,1 个部分是固定的。永远不会从 TableView 中删除。但从第2节开始到第N节,可以删除或插入。从第 2 部分到 N 部分 -> 每个部分也有行
节/段指令有多重要?我注意到它们通常是可选的。另外,我注意到当您包含或不包含它们时,输出大小会发生变化。 我正在使用NASM ,如果有帮助的话。 最佳答案 它们非常重要,因为如果将字符串保存在代码段中
我正在尝试使用已解析并存储在字典中的Firestore数据填充tableview的Sections and Rows,看起来像这样... dataDict = ["Monday": ["Chest",
所以这应该是相当基本的......我正在这样做,但我想要求一些不同的选择。 一种选择是使用“平滑滚动”和 anchor 名称......但我发现这非常不一致。 这是我的 HTML 结构:
我尝试将 3 篇文章嵌套到一个部分中。为什么它们会溢出部分的边界? CSS: article{ border-right:solid 1px grey; height:50%; width:30%;
早上好伙计们,这只是我在这里的第二个问题,所以请耐心等待我和我的最低要求: 我刚刚写了这篇冗长的消息,说明如何将 ID 和 class 命令放在 section 而不是 容器中,以及为什么该部分突然覆
我正在尝试使用以下代码段编码消息: JAXBContext jContext = JAXBContext.newInstance(Iq.class); Marshall
我正在尝试使用以下代码段编码消息: JAXBContext jContext = JAXBContext.newInstance(Iq.class); Marshall
我需要生成一个 PDF 文档,其中我需要一些“章节”(连同其部分和小节)没有编号但仍包含在 ToC 中。 这是我的硕士论文。我正在使用 book 文档类,因为我不喜欢 memoir 默认值。 如果我使
我正在使用正则表达式来尝试匹配 INI 文件中的节 block 。我正在使用书中给出的食谱Regular Expressions Cookbook ,但它似乎对我不起作用。 这是我正在使用的代码: f
我有一个多线程进程,其中文件由多个线程共享(读取和写入)。有没有什么办法可以让一个线程锁定一个文件段,使其他线程无法访问它?我尝试过fcntl(fd, F_SETLKW, &flock),但是这个锁只
Closed. This question needs to be more focused。它当前不接受答案。
我正在尝试使用以下代码片段编码消息: JAXBContext jContext = JAXBContext.newInstance(Iq.class); Marshal
我使用的是分段 tableView。如果我单击 tableview,它总是将索引路径 0 传递给详细 View Controller 。如果我单击第二行,但它的 indexpath pass 总是传递
我有一个多线程进程,其中一个文件由多个线程共享(读取和写入)。有没有什么方法可以让一个线程锁定一个文件段,使其他线程无法访问它?我试过fcntl(fd, F_SETLKW, &flock),但是这个锁
我正在尝试使用以下代码片段编码消息: JAXBContext jContext = JAXBContext.newInstance(Iq.class); Marshal
我想创建一个“术语”部分,其中包含我正在使用的术语的定义,以便每次我在此术语部分中使用这些术语时,都会创建一个指向该定义的链接。 目前,我能想到的最好的方法是: .. |flavor| replace
文档引用 configuring information with stanzas ,但什么是节? 它只是配置子部分的一个花哨名称吗? 最佳答案 您是对的,在此上下文中,节是指 IBM MQ 配置文件
我正在尝试在消息包中接收 XMPP 自定义节。例如, wololo haiooh ... 关键是我知道我会收到一个“custom_sta
为什么这是有效的: (= '(:anything :goes :here) (filter (fn [x] true) '(:anything :goes :here))) 但不是这个? (= (:a
我是一名优秀的程序员,十分优秀!