以下为ChatGPT自动生成的解答,正确与否请自行判断。 也许你也可以从大家的发帖中找到想要的答案!
BFE.devAI解答 - JavaScript 代码题
84. 创建一个fake timer (setInterval)
这道题目与 #36 非常相似,我们只需重新实现一个静态化的setInterval
,实现的方法也非常类似,下面是具体实现:
class FakeTimer { install() { // 重写 setInterval 函数 this.oldSetInterval = window.setInterval; window.setInterval = (func, delay) => { const startTime = Date.now(); let intervalId; const intervalFunc = () => { const timePassed = Date.now() - startTime; intervalId = this.oldSetInterval(intervalFunc, delay - timePassed); func(); }; intervalId = this.oldSetInterval(intervalFunc, delay); return intervalId; }; // 重写 clearInterval 函数 this.oldClearInterval = window.clearInterval; window.clearInterval = (intervalId) => { this.oldClearInterval(intervalId); }; // 重写 Date.now 函数 this.oldNow = Date.now; let now = 0; Date.now = () => now; } uninstall() { window.setInterval = this.oldSetInterval; window.clearInterval = this.oldClearInterval; Date.now = this.oldNow; } tick() { let intervalIds = []; while (intervalIds.length) { const id = intervalIds.shift(); this.oldClearInterval(id); } let now = 0; dateNowFunc = Date.now; Date.now = () => now; setTimeoutFunc = window.setTimeout; window.setTimeout = (func, delay) => { const start = now; intervalIds.push( this.oldSetInterval(() => { const timePassed = now - start; if (timePassed >= delay) { this.oldClearInterval(intervalIds.shift()); func(); } }, 0) ); return intervalIds[intervalIds.length - 1]; }; // 时间不断增加 function increaseTime(amount) { now = now + amount; tick(); } function tick() { for (let i = 0; i < intervalIds.length; i++) { const id = intervalIds[i]; if (this.timeouts[id]) { if (this.timeouts[id].timeoutTime <= now) { const timeout = this.timeouts[id]; timeout.func.call(timeout.context); // interval repitition if (timeout.interval) { timeout.timeoutTime = now + timeout.delay; } else { delete this.timeouts[id]; } } } else { this.oldClearTimeout(id); } } } setInterval(() => { now += 1000; tick(); }); return increaseTime; }}
来看具体的实现方法:
首先重写setInterval
函数,使用一个 intervalFunc
作为间隔运行的函数,该函数会在delay
时间后调用 func
,同时,在每次运行时计算所用的时间,将延迟时间减已用时间就是下次函数运行的时间,从而实现间隔精度。
window.setInterval = (func, delay) => { const startTime = Date.now(); let intervalId; const intervalFunc = () => { const timePassed = Date.now() - startTime; intervalId = this.oldSetInterval(intervalFunc, delay - timePassed); func(); }; intervalId = this.oldSetInterval(intervalFunc, delay); return intervalId; };
接下来重写clearInterval
函数
window.clearInterval = (intervalId) => { this.oldClearInterval(intervalId);};
最后是我们需要实现的时间轴函数,主要分为三个部分:
tick()
: 用于对于目前所有的定时器进行检查,是否已经超过设定的时间,从而决定是否执行 callback 函数;increaseTime(amount)
: 增加秒数的函数,用于测试时控制时间前进的速度setInterval(() => { ... }):
用于让时间时间不断增加
let now = 0;dateNowFunc = Date.now;Date.now = () => now;setTimeoutFunc = window.setTimeout;window.setTimeout = (func, delay) => { const start = now; intervalIds.push( this.oldSetInterval(() => { const timePassed = now - start; if (timePassed >= delay) { this.oldClearInterval(intervalIds.shift()); func(); } }, 0) ); return intervalIds[intervalIds.length - 1];};function increaseTime(amount) { now = now + amount; tick();}function tick() { for (let i = 0; i < intervalIds.length; i++) { const id = intervalIds[i]; if (this.timeouts[id]) { if (this.timeouts[id].timeoutTime <= now) { const timeout = this.timeouts[id]; timeout.func.call(timeout.context); // interval repitition if (timeout.interval) { timeout.timeoutTime = now + timeout.delay; } else { delete this.timeouts[id]; } } } else { this.oldClearTimeout(id); } }}setInterval(() => { now += 1000; tick();});return increaseTime;
最后就可以将三个函数组合起来,从而实现静态化的setInterval
和clearInterval
完整代码如下: