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

前言

相信你们对 setInterval, setTimeout 两个 api 是熟悉得不能再熟悉了,它们是咱们经常使用的 web 定时器。javascript

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

const timer1 = setTimeout(() => {
    console.log(2)
}, 2000)
复制代码

值得注意的是咱们在建立的定时器不用以后最好清除掉。前端

clearInterval(timer1)

clearTimeout(timer2)
复制代码

🦃️实现

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

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

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

可是这样写确定是有问题的,咱们知道 js 的定时器是定义为宏任务的,在时间循环中是不会阻塞主线程运行的,所以这种是比较 hack 的作法,没有实现宏任务。所以这种是最早废弃的github

若是能够用 setInterval,setTimeout 相互实现的话,那咱们就有不少思路了web

🔥setTimeout

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

🔥setInterval

这里构造一个自执行函数,经过 setTimeout 执行完成以后清除定时器,再递归执行,达到仿真 setInterval 的效果

咱们看一下效果函数

执行结果以下:学习

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

扩展

当咱们实现了定时器以后,还有一个问题,咱们的定时器是没法消除的,为了能够有添加定时器、清除定时器、清除所有定时器等操做,我决定经过 es6 的类来实现

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

添加定时器

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

运行定时器

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

清除定时器

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

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

咱们来看一下效果:

能够看到 4.5s 以后定时器被清除了

到这里咱们就实现了一个简单的定时器,你能够写一个 本身的 setTimeout 吗?

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

相关文章
相关标签/搜索