浏览器事件环--节流--防抖--详解
事件环:
-
先执行同步代码
-
如果遇到一个宏任务,会把这个任务放到一个宏任务队列,如果遇到一个微任务,就把这个微任务放到微任务任务中
-
当同步代码执行完毕后,先去清空微任务队列。
-
当微任务队列清空完毕后,从宏任务队列中取出一个宏任务,去执行,在执行过程中,你的宏任务中可能还有同步代码或宏任务或微任务,重复上面的步骤,执行完一个宏任务,肯定要清空微任务队列。这就是所谓的事件环
- 宏任务:ajax,setTimeout,setInterval,DOM事件监听,UI渲染…
- 微任务:promies中的then回调 Mutaion Observer …
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>我是一个p标签01</p>
<!-- <script>
console.log('start')
setTimeout(() => {
console.log('timeout')
})
Promise.resolve().then(() => {
console.log('promise then')
})
console.log('end')
</script> -->
<script>
const p = document.createElement('p');
p.innerHTML = '我是一个p标签02';
document.body.appendChild(p);
const list = document.getElementsByTagName('p')
console.log('length----', list.length)
console.log('start')
setTimeout(() => {
const list = document.getElementsByTagName('p')
console.log('length----', list.length)
alert("阻塞 timeout")
})
Promise.resolve().then(() => {
const list = document.getElementsByTagName('p')
console.log('length----', list.length)
alert("阻塞 promise")
})
console.log('end')
</script>
</body>
</html>
节流 防抖
区别
- 节流不管事件触发多频繁保证在一定时间内一定会执行一次函数
- 防抖是只在最后一次事件触发后才会执行一次函数
防抖实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" id="ipt"> 搜索
<script>
function debouce(fn, delay = 200) {
let timer = 0;
return function () {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
};
let ipt = document.getElementById("ipt");
ipt.addEventListener('keyup', debouce(() => {
console.log("发起搜索", ipt.value);
}, 1000))
</script>
</body>
</html>
防抖 和 节流都是为了避免频繁触发一些回调函数。频繁触发,产生大量EC或大量的请求,造成浏览器性能低下或服务器压力太大。
防抖应用场景:
1)当用户进行了某个行为(例如点击)之后。不希望每次行为都会触发方法,而是行为做出后,一段时间内没有再次重复行为,才给用户响应
2)如:百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发
防抖实现原理: 每次触发事件时设置一个延时调用方法,并且取消之前的延时调用方法。(每次触发事件时都取消之前的延时调用方法)
节流应用场景: 用户进行高频事件触发(滚动),但在限制在n秒内只会执行一次。
节流实现原理:
1)每次触发时间的时候,判断当前是否存在等待执行的延时函数
2)如:就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。
节流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="box" draggable="true" style="width: 100px; height: 100px; background-color: gold; padding: 10px;">
我是一个div
</div>
<script>
function throttle(fn, delay = 100) {
let timer = 0;
return function () {
if (timer) return;
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = 0;
}, delay)
}
}
const box = document.getElementById("box");
box.addEventListener("drag", throttle((e) => {
console.log("鼠标位置:", e.offsetX, e.offsetY);
}, 1000))
</script>
</body>
</html>