浏览器事件环--节流--防抖--详解

事件环:

  1. 先执行同步代码

  2. 如果遇到一个宏任务,会把这个任务放到一个宏任务队列,如果遇到一个微任务,就把这个微任务放到微任务任务中

  3. 当同步代码执行完毕后,先去清空微任务队列。

  4. 当微任务队列清空完毕后,从宏任务队列中取出一个宏任务,去执行,在执行过程中,你的宏任务中可能还有同步代码或宏任务或微任务,重复上面的步骤,执行完一个宏任务,肯定要清空微任务队列。这就是所谓的事件环

  • 宏任务: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>