当前位置: 首页 > news >正文

Web前端入门第 87 问:JavaScript 中 setInterval 和 setTimeout 细节

setIntervalsetTimeout 两者都是用于控制 JS 函数延迟执行,但是在执行机制和用途上还是有点儿差异。

虽然说两者功能上有区别,但在使用上却可以相互模拟各自的功能,大胆的猜测下:也许浏览器内核底层都是同一个方法,只是上层封装出的两个语法糖而已。

语法

两者在语法上极其相似,除了方法名不一样,其他地方没有任何区别:

// 启动定时器
const intervalID = setInterval(func, delay, [arg1], [arg2], ...);
const timeoutID = setTimeout(func, delay, [arg1], [arg2], ...);// 停止定时器
clearInterval(intervalID);
clearTimeout(timeoutID);

执行次数区别

  • setInterval 用于控制函数在指定时间间隔重复执行,直到程序代码手动清除定时任务或浏览器进程退出。
<div id="output"></div><script>(() => {const output = document.getElementById('output')function handle (...args) {output.innerHTML += args.join('、') + '<br>'}// 传入参数 '前端路引'setInterval(handle, 1500, '公众号', '前端路引');})();
</script>

效果:

1

  • setTimeout 用于控制函数在延迟时间后执行一次,然后自动停止。可以通过递归调用模拟 setInterval
<div id="output"></div><script>(() => {const output = document.getElementById('output')function handle (...args) {output.innerHTML += args.join('、') + '<br>'/*默认情况只执行一次,可通过递归调用模拟 setInterval*/setTimeout(handle, 1500, ...args);}// 传入参数 '前端路引'setTimeout(handle, 1500, '公众号', '前端路引');})();
</script>

效果:

2

取消定时器区别

从语法上就能看出来,取消定时器的时需要使用对应的取消方法,不能混用:

  • clearInterval
<button>取消定时器</button>
<div id="output"></div><script>(() => {const output = document.getElementById('output')function handle (...args) {output.innerHTML += args.join('、') + '<br>'}// 传入参数 '前端路引'const intervalID = setInterval(handle, 1500, '公众号', '前端路引');document.querySelector('button').addEventListener('click', () => {clearInterval(intervalID)})})();
</script>

效果:

3

  • clearTimeout
<button>取消定时器</button>
<div id="output"></div><script>(() => {const output = document.getElementById('output')function handle (...args) {output.innerHTML += args.join('、') + '<br>'// 递归调用模拟 setIntervaltimeoutID = setTimeout(handle, 1500, ...args);}// 传入参数 '前端路引'let timeoutID = setTimeout(handle, 1500, '公众号', '前端路引');document.querySelector('button').addEventListener('click', () => {clearTimeout(timeoutID)})})();
</script>

效果:

4

可靠性

重点!

记得最开始学习 JS 的时候就有看到说明,setInterval 的定时器是不管任务执行耗时,反正每次到了时间就要执行,不论是否有耗时任务正在执行。而 setTimeout 启动的定时器,会在等到耗时任务执行之后才会启动下一次任务。

所以,如果 setInterval 设定间隔 100ms,但回调需 200ms 执行,就会造成任务堆积,从而引发性能问题,解决办法就是使用递归 setTimeout 来替代。

语言有些空洞,看例子:

<button>取消 interval 定时器</button>
<div id="output"></div><script>(() => {const output = document.getElementById('output')let times = 0function sleep (ms) {return new Promise(resolve => setTimeout(resolve, ms))}async function handle () {await sleep(1000)output.innerHTML = ++times}const intervalID = setInterval(handle, 200);document.querySelector('button').addEventListener('click', () => {clearInterval(intervalID)})})();
</script>

以上代码由于 handle 任务耗时过长, setInterval 定时器并不会等待任务执行完毕,而是直接执行下一次任务,这就会有一个问题,如果清除定时器,任务不会立即停止,还是有部分执行中的任务正在运行。效果:

5

setTimeout 在处理这种情况时,也会存在问题,虽然每次任务会进行排队,但在点击停止按钮时,由于有异步耗时任务正在执行,清除定时器时,没办法立即终止任务,可以尝试下以下代码:

<button>取消 timeout 定时器</button>
<div id="output"></div><script>(() => {const output = document.getElementById('output')let times = 0function sleep (ms) {return new Promise(resolve => setTimeout(resolve, ms))}async function handle () {await sleep(1000)output.innerHTML = ++times// 递归调用模拟 setIntervaltimeoutID = setTimeout(handle, 200);}let timeoutID =setTimeout(handle, 200);document.querySelector('button').addEventListener('click', () => {// 由于存在异步耗时任务,清除定时器可能会无效clearTimeout(timeoutID)})})();
</script>

效果:

6

使用 AbortController 停止定时器:

<button>取消 timeout 定时器</button>
<div id="output"></div><script>(() => {const output = document.getElementById('output')let times = 0function sleep (ms, signal) {return new Promise(resolve => {setTimeout(() => {if (signal.aborted) {return Promise.reject(new DOMException('操作已被取消', 'AbortError'));}resolve()}, ms)})}async function handle (signal) {await sleep(1000, signal)output.innerHTML = ++times// 递归调用模拟 setIntervaltimeoutID = setTimeout(handle, 200, controller.signal);}const controller = new AbortController();let timeoutID =setTimeout(handle, 200, controller.signal);document.querySelector('button').addEventListener('click', () => {controller.abort();})})();
</script>

上面代码中运用了 AbortController 这个控制器终止定时任务,在任务终止后,直接抛出异常,停止定时器。效果:

7

写在最后

定时器是个好东西,但细节也很多,稍不注意就会出现流程错误,所以在使用时还是需要仔细斟酌~~

setInterval 和 setTimeout 没有绝对的应用场景,两者在使用上都可以互相模拟,只是编写代码量的多少而已。

http://www.wxhsa.cn/company.asp?id=4422

相关文章:

  • 基于Python+Vue开发的农产品商城管理系统源码+运行
  • 多人多次并发
  • B. Alternating Current
  • 虚拟电厂运行机制
  • Reinforcing Image Generation with Collaborative Semantic-level and Token-level CoT - jack
  • 创建我第一个带记忆能力的langchain机器人
  • GitHub超 30000+ star , 超强大的开源项目Supervision
  • 深入解析:【JavaEE】网络原理初识
  • Office文档投毒技术:SHVE中的会话劫持视觉利用新突破
  • 爬虫逆向--Day22Day23--核心实战案例【荔枝网】【WASM学习】
  • 简洁美观!一款值得 Star 的 Java 博客项目!
  • 数据结构与算法-33.图-加权有向图最短路径
  • 白子的情人节礼物
  • 白子的情人节礼物 题解
  • Ubuntu上进行Zookeeper集群部署
  • The Landscape of Agentic Reinforcement Learning综述 - jack
  • A Survey of Reinforcement Learning for Large Reasoning Models - jack
  • r-nacos支持mcp,内置mcp server支持让注册到r-nacos的普通http接口通过r-nacos直接转化成mcp服务对外提供服务。
  • MacOS下微信小程序抓包教程
  • nvm – nodejs版本管理工具
  • 财务系统里面,怎么合并使用两个经费本号
  • 【火电机组、风能、储能】高比例风电电力系统储能运行及配置分析(Matlab代码实现) - 详解
  • 新范式-LLaDA-VLA 基于扩散模型 VLA模型 - jack
  • Redis是如何进行内存管理的?缓存中有哪些常见问题?如何实现分布式锁?
  • 5 遥感与机器学习第三方库安装 - 详解
  • 移远OPENCPU笔记
  • 2025.9.16——1绿
  • Unity游戏开发:互动小游戏的技术实现与运营盈利之道
  • 如何实现主线程捕获子线程异常
  • LGP5688 [CSP-S-JX 2019] 散步 学习笔记