试着分析和试着解题部分是我边写边思考的过程,尝试每推导一步都问自己问题并设法回答。
如果觉得太罗嗦了可以直接跳到其他方法与试着解题的末尾看代码。
如果有更好的办法或者文章中的办法有错误欢迎讨论与交流!
文章目录
参考链接
setTimeout实现setInterval和clearInterval
利用setTimeout和clearTimeout封装setInterval和clearInterval
用setTimeout和clearTimeout简单实现setInterval与clearInterval
试着分析
要用 setTimeout
实现 setInterval
就要知道这两者的定义是什么,有什么区别。
setTimeout()
方法设置一个定时器,该定时器在定时器到期后执行一个函数或指定的一段代码。
setInterval()
方法重复调用一个函数或执行一个代码段,在每次调用之间具有固定的时间延迟。
对比二者在 MDN 文档给的定义,我们不难发现
二者的一个共同点:都是设置一个定时器,并在定时器到期后执行对应的函数或指定的一段代码;
二者的一个不同点:setTimeout
在执行完之后就停止了,setInterval
在执行完之后又开始了下一轮的计时。
这是我们从已有的条件获取到的信息,
现在再回头看看我们的目标是什么?
用 setTimeout
实现 setInterval
从我们获取到的信息出发,我们需要做什么才能达到目标?
或者换个角度,我们需要的达到的目标等价于什么,隐含着什么信息?
用 setTimeout
的功能来实现 setInterval
的功能,所以重点在于功能的实现,而二者的功能区别在前面已经知道了,故此时该做的就是保持共同点,消除不同点。
那么,为了消除不同点,我们需要做什么呢?
需要在定时器到期且执行完函数之后,再一次开启定时器并执行上一次执行的函数,从函数的角度出发就是函数在执行完之后,每隔一段时间就又再次调用自身。
那么,怎么样才能每隔一段时间就调用自身呢?
回头看看条件, setTimeout
能够做到隔一段时间之后调用函数,接着,需要解决的问题就是调用自身了,怎么调用自身呢?这个不难,用递归呗。
(前面的东西可能看一眼题目就能直接想到了,不需要那么多介绍,但我想试着把我们一些默认的条件给点出来,从最开始的条件出发来思考,观察思考的过程)
function mySetInterval(fn, delay) {
setTimeout(() => {
fn();
mySetInterval(fn,delay);
}, delay);
}
这样一看,很轻松就实现了,那这个问题有什么难度,为什么还需要专门来总结?
看似是实现了 setInterval
的功能,但实际上 setInterval
还有一个返回值 intervalID
:
此返回值
intervalID
是一个非零数值,用来标识通过setInterval()
创建的计时器,这个值可以用来作为clearInterval()
的参数来清除对应的计时器 。
也就是说,我们实现的 mySetInterval
并不能完全的替代 setInterval
,只是实现了部分的功能。
那么,为什么我们会出现这个问题呢?从头看一下整理的思考过程,不难发现,问题是出在第一步,我们的对比不够完整,或者说用来比较的信息不够完整。
那么,我们接下来要做什么呢?
实现配套的 myClearInterval
。
这个 myClearInterval
需要有什么功能?
消除指定的 mySetInterval
计时器。
怎么实现这个功能呢?
第一个部分是指定计时器,第二部分是消除计时器。
要指定计时器就是需要给计时器加上指定的标记,以便获取。
消除计时器,可以使用 clearTimeout
来协助实现,也可以不使用这个,因为本质是获取对应的计时器标记,停止计时器的继续运行,前面 mySetInterval
计时器持续运行的原因是 不断地设置新的 setTimeout
计时器,那么,我们阻止这一行为即可。
试着解题
先看看指定计时器,也就是给计时器加上指定的标记。
那么从哪里获取标记呢?
回顾一下我们的条件,不难注意到 setTimeout
函数本身就会返回一个值,用来作为计时器的唯一标识,那我们直接用这个当作 mySetInterval
的返回值不就好了?
试试看。
function mySetInterval(fn, delay) {
let timer = setTimeout(() => {
fn();
// 查看 timer 的变化
console.log(timer); // 2 7 8 ... 19 20 ...
mySetInterval(fn,delay);
}, delay);
return timer;
}
function myClearInterval(timer) {
clearTimeout(timer);
}
/**
* 测试部分,后续方法默认采用如下代码的模板进行测试
*/
// 开启定时器
let t = mySetInterval(()=> {
console.log('mySetInterval'