0

My script is running on a page that runs other scripts which I do not control.

I am running a calculation that takes approximately 20ms to run. (I process a certain list when I init the script and I measure the time per item, and so I can aim to process a list of X elements so that it takes 20ms, on whichever device I am running).

My aim is to impact performance and interactiveness as little as possible, therefore I do not want my calculation to run in the event-loop if it will make it run for longer than 50ms (long task).

I do not know the other calculations that are going to run in this event loop, so I don't know whether I run my 20ms calculation when 40ms were already used in the event loop, or on an event-loop that took only 10ms and has no more tasks, so my calculation will be okay to run in it.

Is there a way for me to make sure my 20ms calculation does not prolong the event-loop over 50ms before I run it?

Notes

  • Can't use Web Workers (my calculation traverses the DOM tree)
  • setTimeout(0,..) is not an option cause when the callback is called I still do not know whether I have enough time on the event loop to run my calculation.
  • my calculation just gathers data about the current state of the DOM. It doesn't update it - so I don't need the render state to be updated.
  • I don't expect to have 0 impact. I am doing a heavy calculation so there's a price to pay. I just want to find the best method to minimize the impact on: TBT (Total Blocking Time) in the main thread.
Yaron
  • 1,655
  • 6
  • 20
  • 38
  • 1
    I don't think it is possible to inspect this, but you can quite easily split up a long task using `setTimeout(0, ..)` or a promise equivalent – mousetail Feb 13 '21 at 20:11
  • What about [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)? – pishpish Feb 13 '21 at 20:12
  • No service workers, no setTimeout (updated in the question's body) – Yaron Feb 13 '21 at 20:23
  • 1
    Service workers are not the same as web workers. + [you can create one from a string](https://stackoverflow.com/questions/10343913/how-to-create-a-web-worker-from-a-string) if that's the problem – pishpish Feb 13 '21 at 22:10
  • You can be sure your task is the first to run in the event loop if it was sheduled by something like setTimeout, from UI events it's less sure. But note that 20ms is already longer than the majority of monitors' refresh rate (60hz or 16.69ms per frame). Also it would be great you explain why Workers are not an option, since they should be the solution. – Kaiido Feb 14 '21 at 00:03
  • @Kaiido I updated in the question - my calculation traverses the DOM tree, and has no effect on render (doesn't manipulate the DOM) – Yaron Feb 14 '21 at 06:32
  • If it locks the event-loop for more than the duration of a frame, it will have an effect on the rendering: the rendering won't be able to happen during this time. – Kaiido Feb 14 '21 at 06:38
  • @Kaiido I need to run my calculation and I'm looking for the best method to do it with the smallest impact. The calculation itself can take 1000ms, so I break it to small tasks which will affect the user and interactiveness as little as possible. – Yaron Feb 14 '21 at 06:42

1 Answers1

2

I think requestIdleCallback should do what I want. It will run only when the browser is idle.

https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback

Yaron
  • 1,655
  • 6
  • 20
  • 38
  • How does that help since the browser is not idle while your task is running? – pishpish Feb 13 '21 at 22:12
  • I could use this callback to run my task. When the browser is idle I can assume my task will run alone without other tasks on the main-thread. (or with fewer tasks) – Yaron Feb 14 '21 at 06:31
  • 1
    How would you find out when the frame started, that is how much time is left in the current frame? Edit: I just noticed `IdleDeadline` in the docs, that's cool. You still have to add timers to your code to know when to abort. – pishpish Feb 14 '21 at 12:43