How to override setTimeout() and setInterval() to allow dynamic adjustments

Viewed 138

I am debugging some complex animation stuff and sometimes I need to slow down time to see what is exactly going on. Since the code is very complex, modification of the animation code is not a viable option. Therefore, I decided to modify the Date class as follows:

let ___date = Date.now();
const ___now = Date.now;
Date = new Proxy(Date, {
  construct(target, args) {
    if (args[0] === undefined) args[0] = this.adjust()
    let date = new target(...args);
    return date;
  },
  get(target, prop, receiver) {
    if (prop === 'now') {
      let date = new Date()
      date.now = () => this.adjust()
      return Reflect.get(date, prop, receiver)
    }
    return Reflect.get(target, prop, receiver)
  },    
  apply(target, thisArg, argumentList) {
    return toString.bind(new Date()).call();
  },
  adjust() {
    // ...
  }
});

This works as desired for new Data() and Date.now(). With this simple modification, I was able to move on, but later I found out that the code is not running as expected, as some parts of the code were still running with the speed that ignored my adjustment. I quickly realized that functions setTimeout() and setInterval() are those that cause my problems.

How can I override setTimeout() and setInterval() so I can adjust time dynamically, i.e. not just when the function is started, but also during ticking?

1 Answers

There is a better way to approach debugging animations, at least in Google Chrome. Open Developer Tools, then from the top-right three-dot menu, choose More Tools → Animations:

Screenshot of additional context menu

This opens an additional pane in the bottom part of the devtools where you can debug animations. You can move back and forth over recorded interactions like a video viewing timeline, as well as slow down animations as far as 10% of their original speed:

Screenshot of the animations pane

You can read more about the whole pane on this page.

Related