turuslan / HackTimer

MIT License
491 stars 93 forks source link

How does this code work? #32

Open NicolasWinsten opened 1 year ago

NicolasWinsten commented 1 year ago

Hello,

many thanks for this hack. But I would like to know how it actually works? How does the webworker keep javascript timers going?

thank you for any help

ivanff commented 1 year ago

yes, it still works, thanks to Ruslan

saurav-codes commented 3 weeks ago

i also want to understand how does it works? do we simply link the script before timer script.?

turuslan commented 3 weeks ago

Hello. Sorry for late comment.

Scripts may create frequent timers

window.setInterval(action, 10ms)

Frequent timers consume more battery (also these timers can be used for annoying things like ads) so browsers throttle window timers (reduce frequency, increase delay) when tab or windows becomes background.

action() after 10ms
action() after 10ms
action() after 10ms
// tab becomes background
action() after 1000ms
action() after 1000ms
...

Although window.setInterval is slowed down, but there seems to be several techniques that work around that.

One of them is using Worker. Worker is created on separate thread from window's ui thread. Seems that browsers don't throttle Worker timers. Worker can postMessage to window, which calls window.onmessage. Seems that browsers don't throttle window.onmessage too.

This library overwrites window.setInterval function and forwards setInterval call to Worker via worker.postMessage, remembering original window callback. Worker calls self.setInterval and worker callback calls self.postMessage to wake window.onmessage, which calls original window callback.

flowchart TB
    subgraph window
        a1("window.setInterval(action)")
        a2("worker.postMessage()")
        a6("worker.onmessage")
        a7("action")
    end
    subgraph worker
        a3("self.onmessage")
        a4("self.setInterval()")
        a5("self.postMessage()")
    end
    a1-->a2-->a3-->a4-->a5-->a6-->a7
    a1-. "action()" .->a6

Library script hacktimer.js overwrites window.setInterval. It must execute before any other script. If some other script will execute before, it will call slow window.setInterval version.