📜  setTimeout (1)

📅  最后修改于: 2023-12-03 14:47:25.597000             🧑  作者: Mango

JavaScript 中的 setTimeout

setTimeout 是 JavaScript 的一个重要函数,它用来延迟执行一个函数。在这篇文章中,我们将会介绍 setTimeout 的基本用法、一些常见的用例以及它可能的一些坑点。

基本用法

setTimeout 接受两个参数:要执行的函数以及延迟的时间(以毫秒为单位)。以下是一个延迟一秒钟后将 "Hello, world!" 打印到控制台的示例:

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

这里的第一个参数是一个匿名函数,第二个参数是指延迟的时间长度,单位是毫秒。

取消一个 setTimeout

setTimeout 对应的,还有一个函数 clearTimeout,用来取消一个已经通过 setTimeout 设置的延迟执行任务。以下是取消上述例子的代码:

var timeoutId = setTimeout(function() {
  console.log("Hello, world!");
}, 1000);

clearTimeout(timeoutId);

这里,我们将 setTimeout 的返回值(一个数值)保存在 timeoutId 变量中,然后在需要取消它的时候调用 clearTimeout 并传入这个数值即可。

常见用例
定时器

通过 setTimeout 可以方便地创建一个定时器,将在指定时间之后执行任务。下面的例子就是一个定时器,每隔一秒钟输出当前时间:

function displayTime() {
  var now = new Date();
  console.log(now.toLocaleTimeString());
}

setTimeout(function repeat() {
  displayTime();

  setTimeout(repeat, 1000);
}, 1000);

这里的匿名函数 repeat 将会周期性地调用自己,并且每隔一秒钟执行一次。注意,在这个例子中我们只调用了一次 setTimeout 因此是一个无限循环执行的定时器。

函数节流

在一些场景下,我们希望某个函数的执行不会过于频繁。例如,在用户输入的时候搜索,我们希望当用户停止输入后再开始搜索。这时候,我们可以使用 setTimeout 来实现函数节流:

function search() {
  // some search logic...
}

var timeoutId = null;

function delayedSearch() {
  if (timeoutId) {
    clearTimeout(timeoutId);
  }

  timeoutId = setTimeout(search, 500);
}

document.querySelector("input").addEventListener("keyup", delayedSearch);

这个例子中,delayedSearch 函数通过 setTimeout 实现了一个延时执行的逻辑。每次触发 keyup 事件后,如果有之前的定时执行任务存在,则先取消它,然后重新设置一个新的延时任务,在 500 毫秒之后执行 search 函数。

动画控制

通过 setTimeout,我们可以控制动画的帧率和刷新间隔时间。例如,下面的例子中,我们将一个元素沿水平方向从左向右移动:

var element = document.querySelector(".animated");

var x = 0;

function animate() {
  x += 10;
  element.style.left = x + "px";

  if (x < 500) {
    setTimeout(animate, 50);
  }
}

animate();

这个例子中,animate 函数将会被周期性地执行,每 50 毫秒一次。在这个函数中,我们不断地改变元素的 left 值,使得元素沿水平方向向右移动。当元素到达一定的位置(这里是 500 像素)之后,停止调用 setTimeout

注意事项
回调函数的 this

在使用 setTimeout 的时候,需要注意回调函数中的 this 指向。在下面的例子中,我们在一个对象上定义了一个方法,这个方法在 1 秒钟后被调用:

var obj = {
  name: "object",

  sayHello: function() {
    console.log("Hello, " + this.name + "!");
  }
};

setTimeout(obj.sayHello, 1000);

由于在这里使用了 obj.sayHello,因此我们期望这个方法中的 this 应该是 obj。但是实际上,这个函数的 this 值是 window

这是因为 setTimeout 中传递了一个函数引用,但是它没有指定 this 值,因此 this 的值会被默认绑定到全局对象上。实际上,传递给 setTimeout 的应该是一个函数调用表达式,例如:

setTimeout(function() {
  obj.sayHello();
}, 1000);

在这个例子中,我们传递了一个匿名函数,而这个函数中又调用了 obj.sayHello 方法。这样的话,sayHello 中的 this 值就会被正确地绑定到 obj 上。

延迟时间的最小值

在不同的浏览器上,setTimeout 的延迟时间可能会有所不同。尤其当延迟时间很小时,这种差异表现得更加明显。并不是所有的浏览器都能正确地处理很小的延迟时间。因此,如果需要严格控制延迟时间,需要特别小心。

总结

通过使用 setTimeout,我们可以实现很多 JavaScript 应用场景中常见的逻辑。从定时器到函数节流,从动画控制到异步请求,都可以用 setTimeout 来实现。但是在使用的过程中,我们也需要特别小心 this 值的绑定和延迟时间的控制。