Show HN: Speed up your site by running JavaScript when the browser is idlenpmjs.com
Cloudef 8 days ago [-]
There's lots of confusion what this is. Basically browser runs a giant eventloop. Whenever you call async function in javascript, it gets put into a queue, and called by the event loop (usually the next execution). This basically makes it so that the async call gets tagged with metadata that tells the event queue "Don't call me unless you have nothing else to call". So basically it keeps the async call at the end of the queue until it's the final call, and that's when the eventloop will call it. The subject is quite misleading as it is not really about idle.
balls187 8 days ago [-]
In defense of the documentation, this is a convenience wrapper around “requestIdleCallback” which from MDN: “queues a function to be called during a browser's idle periods.”

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

k__ 8 days ago [-]
Lol, thanks.

This comment was better than the docs, as usual.

nuko-suke-dev 8 days ago [-]
Sorry for the confusion.

>this is a convenience wrapper around “requestIdleCallback” That's right. I changed README.

https://github.com/hiroki0525/idle-task#features

nmcfarl 9 days ago [-]
What I’d really like to see on this page is more descriptive text. Mainly a description of what’s actually being done by the library. But also a section on when I should use idle-task over Partytown - https://partytown.builder.io/
warpech 9 days ago [-]
I agree. The README file presents it like an alternative to `requestIdleCallback`, while, in fact, it is a convenience wrapper around `requestIdleCallback`. It is a nice idea, but the description makes it confusing.
nuko-suke-dev 8 days ago [-]
>The README file presents it like an alternative to `requestIdleCallback`, while, in fact, it is a convenience wrapper around `requestIdleCallback`. It is a nice idea, but the description makes it confusing.

That's right. I changed README to everyone to understand it.

https://github.com/hiroki0525/idle-task#features

simonpure 9 days ago [-]
As other comments have pointed out, this behavior is enabled by `requestIdleCallback`.

MDN has a good example and looks like this is not supported by Safari -

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

vinibrito 8 days ago [-]
It's always Safari. I never figured out why.
naet 8 days ago [-]
The 3 biggest browser engines are Gecko, Webkit, and Blink.

Gecko is the engine behind Firefox and is maintained by Mozilla, so it has a good number of open source contributors that help fix issues when they are found. It also has some issues occasionally but since it has only a ~3% usage these days you don't get as many complaints.

Blink is used by Chromium (which includes Edge, Chrome, Opera, Brave, and Samsung browsers). It has the biggest market share and probably the most people actively paid to work on it.

Webkit is currently only used by Safari and maintained by Apple alone. (Also all iOS browsers have to use webkit which is why iOS chrome has a lot of the same bugs as iOS safari etc). Apple has a conservative approach to Webkit and doesn't implement as many new features or standards as quickly as the other engines. It has the biggest non blink engine market share so it's usually the outlier when it comes to support issues.

Before 2013 Chromium was webkit based, but that year they made a fork and took their engine in a new direction so Webkit lost some of its previous maintainers.

uncletammy 8 days ago [-]
> Apple has a conservative approach to Webkit and doesn't implement as many new features or standards as quickly as the other engines

This is far too generous. They intentionally withold features in an effort to push people towards their app store.

robocat 8 days ago [-]
Google could let Chrome rot: Microsoft let Internet Explorer rot back in the days before Edge (primarily because Microsoft recognised that browsers would compete with their Windows monopoly: which is exactly what happened).
CharlesW 8 days ago [-]
> MDN has a good example and looks like this is not supported by Safari

It's currently an experimental feature that can be enabled, so hopefully Apple will enable it by default in 2023.

jasonjmcghee 8 days ago [-]
It seems like people are reading this like "add this thing to always busy wait so your site goes faster and drains battery" when in reality it's just saying "schedule low priority tasks to happen at next idle"
brundolf 8 days ago [-]
This is a neat idea, but it's pretty rare that I find myself with a compute-heavy JS task (slow enough to visibly impact performance) that can be neatly split off into an asynchronous process like this (i.e. isn't just part of my UI framework's main rendering process). And the couple times where that has happened, I preferred to spin up a background worker and get true parallelism. The message passing comes with some overhead, but that got swallowed by the fact that it was a heavy task

This looks well-designed and I'm sure somebody has a usecase for it, but I'm not sure I've ever had one

btbuildem 8 days ago [-]
What's the use case? What is "your site" doing that it would need all this computing power?
eyelidlessness 8 days ago [-]
It allows you to temporarily unblock the main thread/renderer before performing a potentially expensive computation. I’ve used this technique (with plain requestIdleCallback) to display incremental UI feedback as a chain of computations progresses. This is in an application I inherited/maintain, with some existing performance problems. I intend to make more substantive performance improvements, but this stopgap measure significantly improves perceived performance, eg by immediately showing the effect of a direct interaction such as a checkbox state change even if the triggered computations may take ~500ms.

The downside is it potentially introduces “jank”, where incremental changes render temporarily, and computation time is somewhat slower overall. In my experience/opinion, the tradeoff is worth it around 100-200ms depending on what’s being unblocked.

dheera 8 days ago [-]
Mine bitcoin on users' computers for you when they are idle?
Kiro 8 days ago [-]
What kind of question is that? Games or applications like Figma obviously require more computing power than a static homepage.
remram 8 days ago [-]
Do they? To do what when the computer is idle?

Those are interactive applications, there's not that much work for them to do when you're not interacting with them.

jasonjmcghee 8 days ago [-]
If you do too much work at once on the main thread, the application will visibly freeze.

Say you need to call a few rest apis that trigger changes to the DOM. If the user is actively interacting with your application, doing an operation like this, say every 5 seconds, could cause momentary lag that feels bad. What if you could wait to do the update until the main thread is free?

remram 8 days ago [-]
Making changes to the DOM seconds later is the part I don't get. Either it's part of interaction and therefore it's urgent, or it's... what?
leipert 8 days ago [-]
At work we have these time strings, e.g. “2 min ago”. We show a tooltip when the user hovers over them. We can defer the initialization of the “show-tooltip” logic because surely those tooltips are less important than other things on the page. Same with links to user profiles.
sheusndudn 8 days ago [-]
collaborative 8 days ago [-]
Question.. is this using multiple threads?

If it isn't, how is this different than async operations?

remram 8 days ago [-]
It is async, the operation is delayed until the processor has nothing important to do.
Kiro 8 days ago [-]
It's not about the computer being idle. It's about waiting for the main thread to be unblocked before doing stuff you would want to do anyway, but now you can schedule it for later to give priority to more urgent tasks. A very common optimization technique in all sorts of software and I don't see why it wouldn't be valid for a web application. Go read https://developer.mozilla.org/en-US/docs/Web/API/Background_... for a better explanation.
remram 8 days ago [-]
You still haven't answered the question. Your link has no example of use cases, though it has warnings about what not to do.
Kiro 8 days ago [-]
Example: In a map application you give priority to rendering the visible map tiles while deferring preloading the surrounding non-visible tiles until the CPU is free. So basically it only renders tiles outside the viewport in a cache if the CPU is not already busy rendering what you're currently looking at.

Any sort of thing that is not urgent and high priority, and where it's no big deal if it's not executed immediately will benefit from being run in requestIdleCallback.

collaborative 8 days ago [-]
Can't reply above. So it's "low-priority" async?
sheusndudn 8 days ago [-]
dewey 8 days ago [-]
They are collaborative applications, if you come back to your screen it could be desireable to have all the changes your coworkers did in the mean time reflected.
postalrat 8 days ago [-]
Figma isn't my site.
nottorp 9 days ago [-]
One of the extensions that suspends idle tabs can protect me from this?
travisd 8 days ago [-]
Lot of people confused here -- the "running JavaScript when the browser is idle" part is a bit misleading.

It doesn't run stuff when you're the tab is backgrounded (browsers already heavily reduce what sites can do when not in focus[1]). Instead, it just lets you delay work until the page isn't doing anything else (such as rendering the page). For example, you might do this when updating a visualization on a page so that the other updates can complete first (e.g., update the input UI and redraw the visualization when that's done).

[1] https://blog.chromium.org/2020/11/tab-throttling-and-more-pe...

toqy 9 days ago [-]
requestIdleCallback isn’t something that you need to protect yourself from. It just executes a function when there’s nothing else happening on your page essentially.
nottorp 9 days ago [-]
You mean my browser still doesn't use enough CPU? I don't want sites that aren't in focus to do anything.
matsemann 9 days ago [-]
The point is to play nice. "I have this task the page needs to do, but I can wait a bit until more convenient". Not "browser is idle, let's mine some bitcoin" as you suggest.
nottorp 9 days ago [-]
Actually I wasn't thinking of bitcoin, but for example of needless auto refreshes and animations.

Seriously, web devs need to learn to respect my battery and electricity bill more.

neweroldguy 8 days ago [-]
This is just a generic “old man shouting at clouds” complaint at this point. You’re not engaging with the material at all.
Kiro 8 days ago [-]
This does not do what you think it does. You're tilting at windmills.

It's not about doing stuff in a tab that isn't in focus. "Idle" refers to the main thread idling in the page you're currently using, so it's about controlling the execution order and priority of JS tasks. E.g. on Google Maps you give priority to rendering the visible map tiles while deferring preloading the surrounding non-visible tiles until the main thread is unblocked (and thus idling).

ovao 8 days ago [-]
The requestIdleCallback API isn’t specific to inactive tabs, and trying to use it to do background work in general is not a Good Idea: the first idle callback is typically going to fire (almost) immediately after painting’s complete, or some handful of milliseconds after.
MichaelCollins 8 days ago [-]
Every web dev seems to think that their site specifically is the reason everybody in the world bought a computer.
bombolo 9 days ago [-]
When there is nothing happening on my page my cpu can go idle.
SketchySeaBeast 9 days ago [-]
A bit of remote browser crypto mining?
Kiro 8 days ago [-]
This comment thread is a serious mess with all sorts of bad faith takes that have nothing to do with the library. Go read https://developer.mozilla.org/en-US/docs/Web/API/Window/requ... and https://developer.mozilla.org/en-US/docs/Web/API/Background_...

This is not used for malicious CPU hijacking or whatever. It's a way to schedule low-priority JS tasks for later when the main thread is unblocked and give priority to more important things. It's a very useful API for when optimizing games or complex web applications.

butz 8 days ago [-]
The main issue with 3rd party scripts is that each one wants to be the first to run. And they are usually the ones that take up the most CPU time and bandwidth.

For some scripts "facade" solution might work even better than running them on idle. Consider a "chat plugin", that usually pops up each time you visit. If we'd replace chat script with simple dummy button, that loads actual script when user really needs to talk to website support - visitor wins as they are not bothered by popups and site loads faster.

Any ideas how to apply this idea for more 3rd party scripts, especially tracking ones?

Etheryte 8 days ago [-]
This whole thing is about performance, but what I'm not seeing any of is actual measurements. Is this actually useful enough to justify all the overhead of writing code in a catered way? Right now I highly doubt it. Is this beneficial at all? After all you're adding some extra overhead and delays which might or might not be made up for by the fact that things are chopped up. The whole of the work doesn't change, you're simply adding breaks in the middle.
nuko-suke-dev 7 days ago [-]
I agree with you. It is difficult to measure how to improve the site performance concretely by using idle-task, but I will do this with my application.
wonnage 8 days ago [-]
This is quite similar to the postTask API currently implemented in Chromium-derived browsers: https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/p...

Of course, none of this works in Safari, where setTimeout is still your only friend.

qwery 9 days ago [-]
I actually like having software and hardware that can be idle. I find it quite peculiar that some app/window/page I'm explicitly not interacting with should be doing work because I'm not interacting with it.
madeofpalk 9 days ago [-]
The idea is that you schedule low priority work to happen with requestIdleCallback (which this is just a wrapper around), so it doesn't impact as much higher-priority tasks like responding to input or animations.

For example, you may schedule periodic API polling (and JSON response parsing) using this API to prioritise user input handling.

I would guess (but not know!) that the browser could de-prioritise these tasks even further when the browser decides to (such as when in the background).

9 days ago [-]
9 days ago [-]
kitsunesoba 9 days ago [-]
Couldn’t this have negative impact on user battery life depending on the weight of the JS or number of open tabs with sites using it? Seems like it might be antagonistic to host OS efforts to to coalesce work and perform it while the CPU is already awake to reduce the number of wakeups and save power, since it specifically waits for browser idle.
flatiron 9 days ago [-]
This is for site performance and not for general OS performance.
Xelynega 9 days ago [-]
"Does your computer run out of battery 10x faster while on the site" should be a site performance issue if it's something in the sites js thats eating the battery.
Kiro 8 days ago [-]
You use this for things you would run anyway, so the total computation time will be the same, but now you will control the execution order and can for example let the main thread handle things that impact the user experience before lesser tasks.
boredumb 8 days ago [-]
You may want to market this as something closer to a 'defer until idle' so it insinuates it's an essential task that can be lower in priority of browser execution. At the moment it does feel like I should start developing a monero miner to monetize my website with it.
Eduard 8 days ago [-]
The logo made me think it's called "oldle Task"
nuko-suke-dev 8 days ago [-]
Certainly.
codedokode 8 days ago [-]
While unrelated to this, I would like browsers to suspend background tabs and maybe even compress their data and unload information that can be restored later (for example, unload images from memory, drop JS bytecode and JIT caches). Majority of websites have no need to do anything when I am not watching them.

Of course there are cases when you need some background activity, for example if you are listening to music or running a program. As I understand, it is extremely difficult do distuinguish between tabs doing useful work and not doing. I would be fine with a manual switch to allow site run in background.

bobbylarrybobby 8 days ago [-]
I'm pretty sure Safari does this, as returning to a heavy tab (say, google sheets) after a long period of it having been in the background takes a few seconds on my 2015 MacBook Pro. I assume that time is spent deserializing the tab’s state.
chrismorgan 9 days ago [-]
The code: https://github.com/hiroki0525/idle-task/blob/main/src/index....

Some initial impressions (based on https://github.com/hiroki0525/idle-task/blob/7e88c8b97c926cf...):

• The cancelIdleCallback fallback implementation will never be defined, so cancelAllIdleTasks will unexpectedly throw an exception in environments like Safari that depend on the polyfill. (Solution: delete lines 14–15.)

• That the simple fallback implementation is a modifying polyfill is not nice, if not clearly stated. Typically better to define it as a local, e.g. `const rIC = typeof requestIdleCallback !== "undefined" ? requestIdleCallback : function …` and subsequently use rIC instead of requestIdleCallback. (Related, I’m not sure quite why you only install the polyfill if self is a thing, are you deliberately ensuring you can’t use this in Node?)

• The default code path is broken, process.env.NODE_ENV will fail in normal browser environments since process is undefined. (And no, no build process gets rid of this, fetch the distributed package and see that its index.js still contains it.)

• Line 74, don’t return a value from a private function if none of the uses use that value; just drop the return keyword.

• Lines 86–93, splitting logArgs out doesn’t make sense to me, it’s functionally harmless, but needless bloat. (I am perennially disappointed at the utterly primitive state of JavaScript bundlers/optimisers/minifiers: especially with TypeScript knowledge of the interfaces being touched, reordering and inlining is a trivial and obvious optimisation that only changes behaviour on bonkers code that deserves to get broken, but no tool will do it, though Closure Compiler’s advanced optimisations mode might be able to be coaxed into doing it—if it even supports spread syntax.)

• The vibe I’m getting is that this works with a mixture of callbacks and promises, and ends up complicated because of it, parts of it feeling like the ’90s and parts like the mid-’10s. The modern approach would be to use abort signals, which… eh, they’re simpler in some cases, more complicated in others. But from this library’s perspective, you could replace the entire interface with just one promise-returning function, which I’d name schedule(task, options), with options including {signal: AbortSignal}. Cancellation would be handled a bit differently, but it’d be more flexible, because it’s left up to the caller how they hook cancellation up (want to be able to cancel a subset of all the tasks together? Easy, give them the same signal). And I think the code of this library would be simplified by going all in on such a pattern.

nuko-suke-dev 8 days ago [-]
Thank you for your good code review! In most cases, I agree with you. I will improve the code as you said gradually.
pastelsky 8 days ago [-]
On a related note – ‘networkIdleCallback’ : Preload assets and data whenever network is idle —

https://github.com/pastelsky/network-idle-callback

Helpful for progressively hydrating features in a page, or loading assets for next interaction

8 days ago [-]
mfbx9da4 9 days ago [-]
Or... use a web worker
balls187 8 days ago [-]
Webworkers run on their own thread.

The point of this is to run low-priority tasks without impacting the main loop, and without the complexity of separate threads.

mfbx9da4 8 days ago [-]
If the task is a long running expensive task, it's going to block the main thread from being responsive to user input. If it's a quick task then you don't need to schedule it. I struggle to see the place for a medium length task which is long enough that it needs to be deferred but short enough that it can't be executed immediately.

What would be an example?

balls187 8 days ago [-]
Sending telemetry data.

It’s low priority, and perhaps it’s quick, but there is no reason it can’t when idle.

8 days ago [-]
bombolo 9 days ago [-]
I have an idea: why not speed up your site by NOT running js at all?
pvg 9 days ago [-]
That's a fine personal choice but don't snarkpoop on other people's Show HN's.

https://news.ycombinator.com/showhn.html

bombolo 8 days ago [-]
If other people's choice had no influence on me, I would totally agree with you.
pvg 8 days ago [-]
It's not a matter of agreement, it's just that this sort of comment is offtopic in Show HN's.
bombolo 8 days ago [-]
> When something isn't good, you needn't pretend that it is,

from the link you provided…

pvg 7 days ago [-]
That's right, except you skipped all the other bits in the link provided -

Be respectful. Anyone sharing work is making a contribution, however modest.

Ask questions out of curiosity. Don't cross-examine.

Instead of "you're doing it wrong", suggest alternatives. When someone is learning, help them learn more.

When something isn't good, you needn't pretend that it is, but don't be gratuitously negative.

Reflexive snark comment that's not even about the thing being shown is none of that. And there's also

Please don't post shallow dismissals, especially of other people's work.

from

https://news.ycombinator.com/newsguidelines.html

bombolo 4 days ago [-]
I did suggest an alternative: not running js.

You clearly don't like my idea, but that doesn't mean it isn't valid.

balls187 8 days ago [-]
The docs are confusing.

This is really about how to make your UI more responsive by performing intensive tasks only when your browser isn’t doing any other tasks related to the javascript code.

In non JS applications, you typically would do this on any thread but the UI thread. But with Javascript, you have the option of doing tasks on the main thread, but only when all other tasks are not being executed. IE a priority queue.

onion2k 9 days ago [-]
But then my contact form won't work!

ducks

SketchySeaBeast 9 days ago [-]
But what if we want a site that's more interactive than a blog?
MichaelCollins 8 days ago [-]
Who's 'we'? The user, or the web dev? Most javascript exists to scratch the itch of the webdev who made it, doing shit no user ever asked for.
SketchySeaBeast 8 days ago [-]
Well, people who don't want to keep refreshing the page to see the site update. That's not just "[scratching] the itch of the webdev who made it".
newbieuser 9 days ago [-]
you are absolutely right. we should completely throw away the development of browser APIs over the years and develop sites with html 4.0
sirwhinesalot 8 days ago [-]
Is... is it bad that I think that might not actually be so bad? I never had an issue with full page reloads of a damn blog, but somehow it's all SPA garbage these days and all the sites have errors in one or more browsers but miraculously keep chugging along (except when they don't and there's a blank page).

At least in the old days if CSS or JS didn't load, you still got a semi-usable page.

Turning HTML+CSS+JS into an application platform has been one of the most fundamentally stupid things we've done as a field and we'll keep paying for it for years on end, second only to not adding slices to C.

RunSet 9 days ago [-]
This but unironically.
dahfizz 8 days ago [-]
The web was a much better place 10 years ago.
somishere 8 days ago [-]
a sweet spot?
togaen 8 days ago [-]
Totally agree with this, actually.
wonnage 8 days ago [-]
Incoming flood of edgelord comments saying they think that would be better
newbieuser 8 days ago [-]
I made this comment to summon them. they come out of their caves when they see something about no js lol
9 days ago [-]