JavaScript 定时器详解

定时器

​ JavaScript 在浏览器中是单线程 执行的,但允许使用定时器指定在某个时间之后或每隔一段时间就执行相应的代码。setTimeout() 用于指定在一定时间后执行某些代码,而 setInterval() 用于指定每隔一段时间执行某些代码。

setTimeout() 方法

​ setTimeout() 方法通常接收两个参数:要执行的代码和在执行回调函数前等待的时间(毫秒)。

​ 第一个参数可以是包含 JavaScript 代码的字符串(类似于传给 eval() 的字符串)或者一个函数,比如:

js 复制代码
// 在 1 秒后显示警告框
setTimeout(() => alert("Hello world!"), 1000);

​ 第二个参数是要等待的毫秒数,而不是要执行代码的确切时间。JavaScript 是单线程的,所以每次只能执行一段代码。为了调度不同代码的执行,JavaScript 维护了一个任务队列 。其中的任务会按照添加到队列的先后顺序执行。setTimeout() 的第二个参数只是告诉 JavaScript 引擎在指定的毫秒数过后把任务添加到这个队列如果队列是空的,则会立即执行该代码。如果队列不是空的,则代码必须等待前面的任务执行完才能执行

​ 调用 setTimeout() 时,会返回一个表示该超时排期的数值 ID。这个超时 ID 是被排期执行代码的唯一标识符,可用于取消该任务。要取消等待中的排期任务,可以调用 clearTimeout() 方法并传入超时 ID,如下面的例子所示:

js 复制代码
// 设置超时任务
let timeoutId = setTimeout(() => alert("Hello world!"), 1000); 
// 取消超时任务
clearTimeout(timeoutId);

​ 只要是在指定时间到达之前调用 clearTimeout(),就可以取消超时任务。在任务执行后再调用 clearTimeout() 没有效果。

注意:所有超时执行的代码(函数)都会在全局作用域中的一个匿名函数中运行,因此函数中的 this 值在非严格模式下始终指向 window,而在严格模式下是 undefined。如果给 setTimeout() 提供了一个箭头函数,那么 this 会保留为定义它时所在的词汇作用域。

setInterval() 方法

​ setInterval() 与 setTimeout() 的使用方法类似,只不过指定的任务会每隔指定时间就执行一次,直到取消循环定时或者页面卸载。setInterval() 同样可以接收两个参数:要执行的代码(字符串或函数),以及把下一次执行定时代码的任务添加到队列要等待的时间(毫秒)。下面是一个例子:

js 复制代码
setInterval(() => alert("Hello world!"), 10000); 

注意:这里的关键点是,第二个参数,也就是间隔时间,指的是向队列添加新任务之前等待的时间。比如,调用 setInterval() 的时间为 01:00:00,间隔时间为 3000 毫秒。这意味着 01:00:03 时,浏览器会把任务添加到执行队列。浏览器不关心这个任务什么时候执行或者执行要花多长时间。因此,到了 01:00:06,它会再向队列中添加一个任务。由此可看出,执行时间短、非阻塞的回调函数比较适合 setInterval()。

​ setInterval() 方法也会返回一个循环定时 ID,可以用于在未来某个时间点上取消循环定时。要取消循环定时,可以调用 clearInterval() 并传入定时 ID。相对于 setTimeout() 而言,取消定时的能力对 setInterval() 更加重要。毕竟,如果一直不管它,那么定时任务会一直执行到页面卸载。下面是一个常见的例子:

js 复制代码
let num = 0, intervalId = null; 
let max = 10; 

let incrementNumber = function() { 
    num++; 
    // 如果达到最大值,则取消所有未执行的任务
    if (num == max) { 
        clearInterval(intervalId); 
        alert("Done"); 
    } 
} 

intervalId = setInterval(incrementNumber, 500);

​ 在这个例子中,变量 num 会每半秒递增一次,直至达到最大限制值。此时循环定时会被取消。这个模式也可以使用 setTimeout() 来实现,比如

js 复制代码
let num = 0; 
let max = 10; 

let incrementNumber = function() { 
    num++; 
    // 如果还没有达到最大值,再设置一个超时任务
    if (num < max) { 
        setTimeout(incrementNumber, 500); 
    } else { 
        alert("Done"); 
    } 
} 

setTimeout(incrementNumber, 500); 

​ 注意在使用 setTimeout() 时,不一定要记录超时 ID,因为它会在条件满足时自动停止,否则会自动设置另一个超时任务。这个模式是设置循环任务的推荐做法。setIntervale() 在实践中很少会在生产环境下使用,因为一个任务结束和下一个任务开始之间的时间间隔是无法保证的,有些循环定时任务可能会因此而被跳过。而像前面这个例子中一样使用 setTimeout() 则能确保不会出现这种情况。一 般来说,最好不要使用 setInterval()。

相关推荐
燃先生._.25 分钟前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
black^sugar2 小时前
纯前端实现更新检测
开发语言·前端·javascript
2401_857600954 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600954 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL4 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据4 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
2402_857583494 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js
java_heartLake5 小时前
Vue3之性能优化
javascript·vue.js·性能优化