JS - 重新学习 定时器

253 阅读4分钟

在 JavaScript 中, 允许我们使用 setInterval(handler,intervalTime,...args) 在每隔一段时间就执行 handler 相应的代码, 而使用 setTimeout(handler, timeout,...args) 在某个时间之后执行指定的 handler 相应的代码. 这两个方法都会 返回一个 number 类型的 ID 值(唯一),可以供我们在执行 handler 之前清空定时器(这样就不会去执行我们的定时任务了)

公共参数说明

type TimerHandler = string | Function; // setTimeout 和 setInterval 的 handler 的类型
args: any[]; // args 对应的是要传递给 handler 的入参
// intervalTime 和 timeout 都是 时间(单位毫秒值),一个是 每隔一段时间就执行(多次执行),
// 一个是在 隔一段时间才执行(一次执行)

定时器中的 handler

所有的 setTimeout 或者 setInterval 函数 的 handler 会在全局作用域中的一个匿名函数中运行,
因此函数中的 this 值在非严格模式下 始终指向 window, 而在严格模式下时 undefined,
如果给 handler 指定为 箭头函数,则 this 会保留为定义它时 所在的 作用域

setTimeout

在 lib.dom.ts 中我们可以看到 setTimeout 的函数声明为

// 设置定时任务
declare function setTimeout(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
// 取消定时任务
declare function clearTimeout(id?: number): void;

setTimeout 不精准时的延时执行

从这个函数中我们可以看到,第一个参数可以是包含 JavaScript 代码的字符串(类似于给 eval() 的字符串)或一个的函数,第二个参数为执行 handler 前要等待的时间;值得注意的是,timeout 是要等待的毫秒数,而不是要执行代码的确切时间,这个原因和 JavaScript 是单线程的原因有关,单线程意味着我们每次只能执行一段代码,为了调度不同的代码,JavaScript 维护了一个 任务队列。其中的任务会按照添加到队列的先后顺序执行,timeout 参数告诉 JavaScript 引擎 在指定的毫秒数过后把任务添加到这个队列,因此在执行 handler 的时候也不是 准确的 在 timeout 毫秒后就执行,因为在队列中我们并不能保证上一个任务在多少时间能能执行完。

setTimeout 清空定时器

在调用 setTimeout 函数时,该函数会返回一个表示超时排期的数值 ID 值,这个 ID 值可以从来取消该任务,而取消的方法是 clearTimeout(id) 的方法

// 设置定时器
const timeoutId = setTimeout(() => alert("hello, timeout"),1000);

// 在执行 hanlder之前取消定时器后, 便不会执行 alert 的操作
clearTimeout(timeoutId)

setInterval

在 lib.dom.ts 文件中我们可以找到 setInterval 的函数声明为

// 设置定时任务, 每隔一段时间就会把 任务 添加到 任务队列里边去
setInterval(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
// 取消定时任务
declare function clearInterval(id?: number): void;

setInterval 和 clearInterval 的使用方法和特点都类似, 如, setInterval 和 setTimeout 中的 handler 在执行的时候都不是在 设定的时间之后 就可以执行,他们代表的含义都是 在 timeout 之后才把 handler 放入任务队列里边,而不是说在 timeout 之后就立即执行 handler; clearTimeout / clearInterval 都接受 一个定时器返回的的定时器 ID, 在执行 对应的 handler 之前清空了定时器后, hanlder 都不会执行。

setTimeout 和 setInterval 的区别

  • setInterval 指定的任务会每隔指定时间就执行一次(循环多次执行), 直到取消循环定时器或者页面卸载。setTimeout 是在 指定的时间后执行指定任务(一次);setInterval 的间隔时间是按照指定的时间 就把 指定任务添加到队列里边去,浏览器不会关心这个任务什么时候执行或者要话多少时间,因此会在设置的间隔时间里就把 指定的时间放到 队列里边去,setInterval 时候执行时间短、非阻塞的回调函数
  • setTimeout 可以模拟 setInterval, 且不需要记录 超时 ID,在满足条件后悔自动停止, 而 setInterval 需要记录 循环 ID, 然后使用 clearInterval 来清除任务(不然定时任务会一直执行到页面卸载)
  • 清除的定时器方法不同,这个就不说了

谢谢你的阅读,如有错误,欢迎指正!