Skip to content

Latest commit

 

History

History
executable file
·
231 lines (164 loc) · 5.56 KB

第12章 定时器与延迟函数.md

File metadata and controls

executable file
·
231 lines (164 loc) · 5.56 KB

一、延时函数

在实际开发中,我们可能会延时执行某一个操作,比如主页加载完之后,延时 n 秒弹出广告,这个时候我们就需要用到延时函数啦。

1. 语法形式

语法形式:

setTimeout(callback, delay);

语法解读:

  • callback:回调函数,延迟时间结束之后调用的函数
  • delay:延迟时间,单位 ms

2. 代码示例

console.log("登陆中, 请稍后...");
setTimeout(function(){
    console.log("欢迎木子李!");
}, 2000);
console.log("...");

登陆中, 请稍后...
...
欢迎木子李!

注意:延时函数为异步操作,不会阻塞线程。

3. 取消延时

在延时的过程中,有时因为某种情况,不执行延时函数了,那么我们就需要取消延时,语法如下:

clearTimeout(t)

代码示例:

console.log("登陆中, 请稍后...");
// 定义变量记录延时函数
var t = setTimeout(function(){
    console.log("欢迎木子李!");
}, 5000);
console.log("...");
// 清除延时函数
clearTimeout(t);

// 登陆中, 请稍后...
// ...

二、定时器

在实际开发中,如果我们需要每隔一段时间就做某个事情的时候,我们可以使用定时器,比如在做倒计时功能的时候就可以用到定时器函数。

1. 语法形式

语法形式:

setInterval(callback, interval);

语法解读:

  • callback:回调函数,每隔指定时间都会执行一次回调函数
  • interval:时间间隔,单位ms

2. 代码示例

var count = 10;
setInterval(function() {
    console.log(--count);
}, 1000);

上述代码,每隔1秒钟就会让 count 变量自减 1 并输出。

3. 清除定时器

清除定时器和清除延时函数一样,只需使用 clearInterval() 函数即可。

var count = 5;
// 定义变量存储定时器
var t = setInterval(function() {
    if(count == 0) {
        console.log("时间到!");
        // 清除定时器
        clearInterval(t);
        return;
    }
    console.log(--count);
}, 1000);

三、扩展

1. 倒计时

思路:

  • 时间差计算(ms):目标时间 - 当前时间

  • 将时间差(ns)转换为天、时、分、秒:

    let day     = Math.floor(ms / 1000 / 60 / 60 / 24);
    let hours   = Math.floor(ms / 1000 / 60 / 60 % 24);
    let minutes = Math.floor(ms / 1000 / 60 % 60);
    let seconds = Math.floor(ms / 1000 % 60);

比如,呈现一个距离2023年国庆的倒计时功能:

function countdown(targetDate, callback) {
  var d, ms, t, day, hours, minutes, seconds;
  var format = (v) => v.toString().padStart(2, '0');
  t = setInterval(function () {
    d = new Date();
    ms = targetDate - d;
    if (ms > 0) {
      day = format(Math.floor(ms / 1000 / 60 / 60 / 24));
      hours = format(Math.floor((ms / 1000 / 60 / 60) % 24));
      minutes = format(Math.floor((ms / 1000 / 60) % 60));
      seconds = format(Math.floor((ms / 1000) % 60));
      callback({ day, hours, minutes, seconds });
    } else {
      clearInterval(t);
    }
  }, 1000);
}

countdown(new Date('2023/10/01'), function (r) {
  console.log(
    `距离2023年国庆还有${r.day}${r.hours}${r.minutes}${r.seconds}秒`
  );
});

2. 函数防抖

2.1. 概念

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间

2.2. 使用场景

比如搜索功能,在搜索内容变化后就触发搜索事件请求接口,有时候我们输的内容很长,在没有输完的时候就触发了事件,这样就造成了很多无用的请求,这时候就需要用到防抖函数,来让其在搜索内容变化后的指定时间内如果没有再更改才发起请求。

2.3. 实现

思路:每次触发事件时都取消之前的延时调用方法

function debounce(callback, delay = 500) {
  let t = null;
  return function (...args) {
    clearTimeout(t);
    t = setTimeout(() => {
      callback.apply(this, args);
    }, delay);
  }
}

使用:

const input = document.querySelector("input");
input.oninput = debounce(function () {
  console.log('__Search__');
});

3. 函数节流

3.1. 概念

高频事件触发,在n秒内只会执行一次,所以节流会稀释函数的执行频率。就比如老板给你布置了一个任务,在指定时间内你只需要专心完成老板布置的任务即可,期间如果产品经理过来给你派发任务的时候,你可以直接忽略(当然实际情况是作为苦逼的程序猿来讲忽略是不可能的)。

3.2. 使用场景

函数节流的应用场景一般是 onresizeonscroll 等这些频繁触发的函数,比如你想获取滚动条的位置,然后执行下一步动作。如果监听后执行的是DOM操作,这样的频繁触发执行,可能会影响到浏览器性能,甚至会将浏览器卡崩,所以我们可以规定他多少秒执行一次。

3.3. 实现

思路:每次触发事件时都判断当前是否有等待执行的延时函数

function throttle(callback, delay = 500) {
  // 1. 设置一个开关
  let isOn = true;
  return function (...args) {
    // 2. 如果当前正在执行某个任务,则忽略
    if (!isOn) return;
    // 3. 更新开关状态
    isOn = false;
    // 4. 启用定时器
    setTimeout(() => {
      callback.apply(this, args);
      isOn = true;
    }, delay);
  }
}

使用:

window.onresize = throttle(function (event) {
  console.log(event.target.innerWidth, event.target.innerHeight);
});