目 录CONTENT

文章目录

你不知道的JS定时器:从原理到实践的全面指南

萧瑟
2023-06-24 / 0 评论 / 0 点赞 / 412 阅读 / 5,770 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-07-03,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

定时器相关的面试题:

1. 什么是JS定时器?有哪两种方法可以创建定时器?
2. setTimeout()和setInterval()的区别是什么?如何取消定时器?
3. 如何使用箭头函数来解决定时器中的this问题?
4. 定时器的延迟参数是如何被转换为一个有符号32位整数的?这会导致什么样的限制?
5. 定时器的回调函数是在哪个执行上下文中运行的?为什么?
6. 如何使用Promise或async/await来封装定时器函数?
7. 如何使用requestAnimationFrame()来替代setInterval()实现动画效果?
8. 如何使用Date对象来测量定时器的执行时间?
9. 定时器的执行顺序是如何受到事件循环和任务队列的影响的?
10. 如何使用递归的setTimeout()来实现类似于setInterval()的功能?

本篇目录:

1、什么是定时器
2、setTimeout()
3、setInterval()
3.1、实现每隔 1s 执行一次
3.2、可用来做一个时钟
4、clearTimeout()、clearInterval()
5、setTimeout(f, 0)
6、异步与回调
7、函数节流

1、什么是定时器

js定时器是一种在指定的时间间隔或者延迟后执行某个函数或者代码段的方法。js定时器有两种类型:一种是setInterval,它会重复执行某个函数或者代码段,直到被清除或者页面被关闭;另一种是setTimeout,它只会执行一次某个函数或者代码段,然后停止。js定时器可以用来实现动画效果,轮播图,倒计时等功能。

2、setTimeout()

setTimeout()是一个全局函数,用setTimeout()方法设置一个定时器,该定时器会在到期后执行一个函数或代码。

语法:

setTimeout(callback, delayTime, param1, param2, /* … ,*/ paramN)

参数:

callback:当定时器到期后,需要执行的函数。
delayTime:定时器需要等待的时间,单位是毫秒(无需带时间单位),当数值为0时,函数会立即执行。
param1, param2, /* … ,*/ paramN:当定时器到期后,它们会作为参数传递给callback函数。

例如,以下代码会在3秒后打印"Hello, world!":

setTimeout(() => {
  console.log("Hello, world!");
}, 3000);

3、setInterval()

setInterval()与setTimeout()不同点在于:setTimeout()将函数延期执行,setInterval()是将函数每个规定时间执行一次。

语法:

setInterval(function, milliseconds, param1, param2, ...)

参数:

function:要重复执行的函数或代码块。
milliseconds:每次执行的时间间隔(以毫秒为单位)。
param1, param2, ...:可选的参数,用于传递给函数。

setInterval()函数会返回一个整数值,表示定时器的标识符。可以使用clearInterval()函数来取消定时器,传入setInterval()返回的标识符作为参数。

// 例如,以下代码会在每秒钟打印一次“Hello World”:

var timer = setInterval(function() {
  console.log("Hello World");
}, 1000);

// 取消定时器
clearInterval(timer);

3.1 实现每隔 1s 执行一次

要实现每隔 1s 执行一次,我们可以将第二个参数设置为1000毫秒,表示时间间隔为1秒。例如,以下代码会在每隔 1s 打印一条消息到控制台:

setInterval(function() {
  console.log("Hello, world!");
}, 1000);

3.2 可用来做一个时钟

//用setInterval()实现一个时钟的方法如下:

//首先,创建一个函数,用来获取当前的时间,并将其格式化为时:分:秒的形式。
function getTime() {
  //获取当前的日期对象
  let date = new Date();
  //获取当前的小时,分钟和秒数
  let hour = date.getHours();
  let minute = date.getMinutes();
  let second = date.getSeconds();
  //如果小时,分钟或秒数小于10,就在前面补0
  if (hour < 10) {
    hour = "0" + hour;
  }
  if (minute < 10) {
    minute = "0" + minute;
  }
  if (second < 10) {
    second = "0" + second;
  }
  //返回时:分:秒的字符串
  return hour + ":" + minute + ":" + second;
}

//然后,将这个函数赋值给一个变量,例如clock。
let clock = getTime;

//其次,创建一个元素,用来显示时钟。
//可以使用document.getElementById()或者document.querySelector()等方法来获取页面上的一个元素,并将其赋值给一个变量,例如display。
let display = document.getElementById("clock");

//最后,使用setInterval()函数,设置一个定时器,每隔一秒钟就调用一次clock函数,并将其返回的值赋给display元素的innerHTML属性。
//这样,就可以在页面上实时显示当前的时间了。
setInterval(function() {
  display.innerHTML = clock();
}, 1000);

4、clearTimeout()、clearInterval()

clearTimeout()和clearInterval()是JavaScript中的全局函数,用于取消之前通过setTimeout()和setInterval()设置的定时器。

setTimeout()和setInterval()都接受两个参数:一个是要执行的函数,一个是时间间隔(以毫秒为单位)。如果要取消定时器,需要将setTimeout()或setInterval()的返回值(一个数字标识符)作为参数传递给clearTimeout()或clearInterval()。

值得注意的是,setTimeout()和setInterval()使用共享的ID池,意味着在技术上可以混用clearTimeout()和clearInterval()。但是,为了清楚起见,应当避免这样做。

下面是一些示例代码:

// 使用setTimeout()创建一个在1秒后弹出"Wake up!"的定时器
var timeoutID = setTimeout(function(){
  alert("Wake up!");
}, 1000);

// 使用clearTimeout()取消定时器
clearTimeout(timeoutID);

// 使用setInterval()创建一个每隔1秒打印"Hello"的定时器
var intervalID = setInterval(function(){
  console.log("Hello");
}, 1000);

// 使用clearInterval()取消定时器
clearInterval(intervalID);

如果创建定时器setInterval()的时候用变量保存了它,那清除的时候直接用clearInterval()就可以了,但如果有的定时器在创建的时候没有用变量保存,就不能用上边的方法了。

我们可以采取暴力手段,将所有的定时器全部清除

let end = setInterval(function () { }, 10000);
for (let i = 1; i <= end; i++) {
    clearInterval(i);
}

操作原理是:我们并不知道当前一共有多少个定时器,只知道定时器对应的数是从1开始逐渐递增的,那我们只需要再创建一个定时器,并将新创建的定时器ID用end存储起来,接下来通过循环清除掉1到end个定时器,那么就相当于将所有的定时器都清除了。

5、setTimeout(f, 0)

setTimeout(f, 0)是一个JavaScript函数,它的作用是在当前执行栈的最后执行一个函数f。它并不是立即执行f,而是将f放入一个事件队列中,等待当前执行栈中的所有任务完成后,再从事件队列中取出f执行。这样可以实现一些异步操作,比如在DOM渲染完成后执行一些回调函数。例如:

console.log('开始');
setTimeout(() => {
    console.log('延时执行');
}, 0);
console.log('结束');

// 开始
// 结束
// 延时执行

6、异步与回调

JavaScript是一种单线程的语言,也就是说,同一时间只能执行一个任务。为了处理一些耗时的操作,例如网络请求、文件读写等,JavaScript采用了异步编程的模式,即将这些操作放在一个任务队列中,等待主线程空闲时再执行。

setTimeout()和setInterval()是两个常用的异步编程的方法,它们都可以在指定的时间后执行一个函数或者一段代码。它们的区别是,setTimeout()只执行一次,而setInterval()会重复执行,直到被清除。

要实现异步与回调的功能,我们可以利用setTimeout()和setInterval()来模拟一些延迟的操作,并在操作完成后执行一个回调函数。例如:

// 定义一个模拟网络请求的函数
function request(url, callback) {
  // 使用setTimeout来模拟网络延迟
  setTimeout(function() {
    // 假设url是一个有效的地址,返回一个数据对象
    var data = {name: "Alice", age: 20};
    // 调用回调函数,并将数据作为参数传递
    callback(data);
  }, 1000); // 延迟1秒
}

// 调用request函数,并传入一个url和一个回调函数
request("https://example.com/api/user", function(data) {
  // 在回调函数中处理返回的数据
  console.log("The user's name is " + data.name);
  console.log("The user's age is " + data.age);
});

// 定义一个模拟定时器的函数
function timer(seconds, callback) {
  // 使用setInterval来模拟定时器
  var interval = setInterval(function() {
    // 每秒打印一次剩余时间
    console.log("Time left: " + seconds + "s");
    // 减少剩余时间
    seconds--;
    // 如果剩余时间为0,清除定时器,并调用回调函数
    if (seconds === 0) {
      clearInterval(interval);
      callback();
    }
  }, 1000); // 每隔1秒执行一次
}

// 调用timer函数,并传入一个秒数和一个回调函数
timer(5, function() {
  // 在回调函数中打印结束信息
  console.log("Time's up!");
});

7、函数节流

函数节流,用于控制函数的执行频率,以避免过度消耗资源或造成性能问题。函数节流的一种常见方法是利用setTimeout()和setInterval()这两个JavaScript内置函数。setTimeout()函数可以在指定的时间后执行一个回调函数,而setInterval()函数可以在指定的时间间隔内重复执行一个回调函数。利用这两个函数,我们可以实现函数节流的效果,例如:

// 定义一个要节流的函数
function doSomething() {
  console.log('Doing something...');
}

// 定义一个节流器函数,接受一个要节流的函数和一个时间间隔作为参数
function throttle(func, interval) {
  // 定义一个变量,用于存储定时器的ID
  let timer = null;
  // 返回一个新的函数,这个函数会在指定的时间间隔内最多执行一次要节流的函数
  return function() {
    // 如果定时器不存在,说明可以执行要节流的函数
    if (!timer) {
      // 执行要节流的函数,并将this和arguments传递给它
      func.apply(this, arguments);
      // 设置一个定时器,在指定的时间间隔后清除定时器
      timer = setTimeout(() => {
        timer = null;
      }, interval);
    }
  };
}

// 使用节流器函数包装要节流的函数,设置时间间隔为1000毫秒
let throttledDoSomething = throttle(doSomething, 1000);

// 每200毫秒调用一次节流后的函数
setInterval(throttledDoSomething, 200);

// 输出结果:
// Doing something...
// (一秒后)
// Doing something...
// (一秒后)
// Doing something...
// (一秒后)

往期精彩

1、了解 iframe 内嵌框架:深度解析其工作原理

2、卸载软件神器Bulk Crap Uninstaller,让电脑不再臃肿!

3、正则表达式:你必须掌握的技能之一 · 概念


weixin

0

评论区