前言
当谈到 JavaScript 编程语言最基本的概念时,定时器就是一个必须掌握的知识点。在编写网站时,你经常会遇到需要在一定时间间隔内执行一些代码的情况。这时候,JavaScript 定时器就可以派上用场了。
什么是定时器?
JS
定时器是一种非常常见的 JavaScript
编程方法,用于周期性地执行指定的代码片段。JS
定时器可以用来实现许多非常实用的效果,例如周期性地更新页面内容、动态地加载数据、实现动画效果等等。
在 JavaScript
中,有两种主要的定时器方法: setTimeout()
和 setInterval()
。这两个方法都可以用来周期性地执行指定的代码片段,但它们之间有一些关键的区别。
setTimeout() 创建
setTimeout()
方法也可以周期性地执行指定的代码片段,但它只会执行一次,然后等待指定的时间后再次执行。简单来说就是指定时间后执行一段代码(延迟执行)。
setTimeout()
中共有 4
个参数,这里只使用两个参数,第一个参数是一个箭头函数,第二个参数表示在多少秒后执行这个箭头函数。
let timer = setTimeout(() => {
console.log("我将在两秒后输出!");
}, 2 * 1000);
clearTimeout() 清除
clearTimeout()
方法用于取消一个定时任务,前提是这个定时任务还没被触发。
let timer = setTimeout(() => {
console.log("我将在两秒后输出!");
}, 2 * 1000);
clearTimeout(timer); //定时任务取消,两秒后将不会有任何输出
setInterval() 创建
setInterval()
方法允许我们周期性地执行指定的代码片段,而这个代码片段会一直执行下去。简单来说就是每隔一段时间执行一段代码(间隔执行)。
setInterval()
方法的参数用法与 setTimeout()
一致,区别在于,这个定时器会一直循环执行。
let timer = setInterval(() => {
console.log("每隔一秒我将输出一次")
}, 1000)
控制台打印
setInterval() 清除
clearInterval()
用于取消循环定时任务。
let timer = setInterval(() => {
console.log("每隔一秒我将输出一次")
}, 1000)
setTimeout(() => {
clearInterval(timer);// 将在3秒时被清除
}, 3000);
控制台打印
定时器与递归
递归函数是一种特殊的函数,它可以调用自身来完成某些任务。在 JavaScript
中,通过递归函数与定时器可以用来解决许多复杂的问题。
下面是一个最简单的栗子
<template>
<div>{{num}}</div>
</template>
<script>
export default {
data() {
return {
num: 0,
};
},
mounted() {
this.recursion();
},
methods: {
recursion() {
this.num++;
setTimeout(() => {
this.recursion();
}, 1000);
},
},
};
</script>
实现效果
深入理解
因为 JavaScript
的执行环境是单线程的,即默认情况下是同步加载的,也就是说 JavaScript
的加载是阻塞的。在同一时间内它只能完成一件事,自上而下执行,下面的代码等待上面的代码解析完成。在这种情况下,后面的代码其实就是被阻塞了。阻塞就意味着等待,等待就意味着用户体验,用户体验一来,那必须得使劲想办法,所以同步和异步出现了。
同步和异步
- 同步操作:队列执行。
- 异步操作:并线执行。
异步的任务不具有阻塞效应。同步任务都是在主线程中执行,形成了一个执行栈,直到主线程空闲时,才会去事件队列中查看是否有可执行的异步任务,如果有就推入主进程中。
异步任务在 JavaScript
中是通过回调函数实现异步的,一旦使用了 setTimeout()
,里面的回调函数就是异步代码,但是这里面的代码不会立马执行,而是要等待主队列为空,并达到定的延时时间才会执行。
运行机制
setTimeout()
和 setInterval()
的运行机制是,将指定的代码移出本次执行,等到下一轮事件循环时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮事件循环时重新判断。
这意味着,setTimeout()
和 setInterval()
指定的代码,必须等到本轮事件循环的所有同步任务都执行完,再等到本轮事件循环的“任务队列”的所有任务执行完,才会开始执行(宏任务)。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证在时间内执行。
setTimeout(function () {
console.log("异步任务执行");
}, 0);
function a(x) {
console.log("a() 开始运行");
b(x);
console.log("a() 结束运行");
}
function b(y) {
console.log("b() 开始运行");
console.log(y);
console.log("b() 结束运行");
}
console.log("同步任务开始");
a("hello world");
console.log("同步任务结束");
控制台打印结果