likes
comments
collection
share

你会用 setInterval, setTimeout 互相实现吗?

作者站长头像
站长
· 阅读数 0

前言

相信大家对 setInterval, setTimeout 两个 api 是熟悉得不能再熟悉了,它们是我们常用的 web 定时器。

const timer1 = setInteral(() => {
    console.log(1)
}, 1000)

const timer1 = setTimeout(() => {
    console.log(2)
}, 2000)

值得注意的是我们在创建的定时器不用之后最好清除掉。

clearInterval(timer1)

clearTimeout(timer2)

🦃️实现

那我们今天来讨论一下,如何实现一个定时器呢?

关于 setTimeout, 同事给出了这样的实现:

你会用 setInterval, setTimeout 互相实现吗?

逻辑也非常清晰,在函数内部构造一个循环堵住程序,等到时间到后跳出循环执行 callback,相当于开闸泄洪。

但是这样写肯定是有问题的,我们知道 js 的定时器是定义为宏任务的,在时间循环中是不会阻塞主线程运行的,因此这种是比较 hack 的做法,没有实现宏任务。因此这种是最先废弃的

如果可以用 setInterval,setTimeout 相互实现的话,那我们就有很多思路了

🔥setTimeout

你会用 setInterval, setTimeout 互相实现吗?

我的 setTimeout 是这样实现的,通过 setInterval 构造一个定时器,到第一次执行时清除定时器,执行回调函数

🔥setInterval

你会用 setInterval, setTimeout 互相实现吗? 这里构造一个自执行函数,通过 setTimeout 执行完成之后清除定时器,再递归执行,达到仿真 setInterval 的效果

我们看一下效果

你会用 setInterval, setTimeout 互相实现吗?

执行结果如下:

你会用 setInterval, setTimeout 互相实现吗?

我们看到这里的定时器是没有阻碍主执行粘的,基本达到了我们的目的

扩展

当我们实现了定时器之后,还有一个问题,我们的定时器是无法消除的,为了可以有添加定时器、清除定时器、清除全部定时器等操作,我决定通过 es6 的类来实现

你会用 setInterval, setTimeout 互相实现吗?

思路中的大致结构是这样,我们维护一个定时器栈,这个类有 add,run,clear,clearAll 等方法,可以添加,清除,运行定时器,有了这个思路之后我们一步一步来实现

添加定时器

你会用 setInterval, setTimeout 互相实现吗?

原理很简单,添加定时器就是直接把数据推入我们的栈中,推入前需要做一下简单的数据校验

运行定时器

你会用 setInterval, setTimeout 互相实现吗?

通过 name 在栈中查找,找到对应的定时器之后执行,这里需要用到 setTimeout 来实现 setInterval,执行方式和上面一样。

清除定时器

你会用 setInterval, setTimeout 互相实现吗?

原理就是找到对应的定时器,在栈中删掉,这样在 run 的递归函数中找不到对应的定时器就无法执行。清除全部定时器直接清空栈就好。

到这里我们实现了一个简单的 setInterval

你会用 setInterval, setTimeout 互相实现吗?

我们来看一下效果:

你会用 setInterval, setTimeout 互相实现吗?

你会用 setInterval, setTimeout 互相实现吗?

可以看到 4.5s 之后定时器被清除了

到这里我们就实现了一个简单的定时器,你可以写一个 自己的 setTimeout 吗?

关注 前端 100 问,一起学习,持续扩展中