目录
- 写一个定时器,每次间隔不同的时间
- setInterval 缺点 与 setTimeout 的不同
- 两个定时器的延迟时间都是不准确的
- 因为window.setTimeout,所以定时器中的this指向window
一、写一个定时器,每次间隔不同的时间
写一个 mySetInterVal(fn, a, b),每次间隔 a,a+b,a+2b,...,a+nb 的时间,然后写一个 myClear,停止上面的 mySetInterVal
1) 思路
通过
setTimeout+递归模拟实现setInterval
递归执行
this.start来实现setInterval的效果
function MySetInterVal(fn, a, b) {
this.a = a;
this.b = b;
this.time = 0; // 变化值 计算 延迟事件
this.handle = -1; // 用于清除定时器
this.start = () => {
//通过setTimeout+递归模拟实现 setInterVal
this.handle = setTimeout(() => {
fn(); // 定时器回调
this.time++;
this.start(); // 递归调用自己
console.log( '延迟执行时间:', this.a + this.time * this.b);
}, this.a + this.time * this.b);
}
this.stop = () => {
clearTimeout(this.handle);
this.time = 0;
}
}
var a = new mySetInterVal(() => {console.log('123')},1000, 2000 );
a.start();
a.stop();
// 运行结果
二、setInterval 缺点 与 setTimeout 的不同
再次强调,
定时器指定的时间间隔,表示的是何时将定时器的代码添加到消息队列,而不是何时执行代码。所以真正何时执行代码的时间是不能保证的,取决于何时被主线程的事件循环取到,并执行。
在
setInterval 被推入任务队列时,如果在它前面有很多任务或者某个任务等待时间较长比如网络请求等,那么这个定时器的执行时间和我们预定它执行的时间可能并不一致
每个 setTimeout 产生的任务会直接 push 到任务队列中;而 setInterval 在每次把任务 push 到任务队列前,
都要进行一下判断(看上次的任务是否仍在队列中,如果有则不添加,没有则添加)。
三、 两个定时器的延迟时间都是不准确的
因为在定时器当中会有一些耗时的任务时
setTimeout本身运行就需要额外的时间运行结束之后再激活下一次的运行。这样会导致一个问题就是时间不断延迟,原本是1000ms的间隔,再setTimeout无意识的延迟下也许会慢慢地跑到总时长2000ms的偏差。
四、 因为window.setTimeout,所以定时器中的this指向window
参考
总结
-
通过
setTimeout+递归模拟实现setInterval -
再次强调,
定时器指定的时间间隔,表示的是何时将定时器的代码添加到消息队列,而不是何时执行代码。所以真正何时执行代码的时间是不能保证的,取决于何时被主线程的事件循环取到,并执行。 -
每个 setTimeout 产生的任务会直接 push 到任务队列中;而 setInterval 在每次把任务 push 到任务队列前,
都要进行一下判断(看上次的任务是否仍在队列中,如果有则不添加,没有则添加)。 -
setTimeout比setInterval延迟时间相对准确一些 -
两个定时器的延迟时间都是不准确的 -
因为
window.setTimeout,所以定时器中的this指向window