[HN Gopher] Show HN: Speed up your site by running JavaScript wh...
       ___________________________________________________________________
        
       Show HN: Speed up your site by running JavaScript when the browser
       is idle
        
       Author : nuko-suke-dev
       Score  : 83 points
       Date   : 2022-11-24 12:53 UTC (10 hours ago)
        
 (HTM) web link (www.npmjs.com)
 (TXT) w3m dump (www.npmjs.com)
        
       | chrismorgan wrote:
       | 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.
        
       | btbuildem wrote:
       | What's the use case? What is "your site" doing that it would need
       | all this computing power?
        
         | dheera wrote:
         | Mine bitcoin on users' computers for you when they are idle?
        
         | Kiro wrote:
         | What kind of question is that? Games or applications like Figma
         | obviously require more computing power than a static homepage.
        
           | postalrat wrote:
           | Figma isn't my site.
        
           | remram wrote:
           | 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.
        
             | dewey wrote:
             | 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.
        
             | jasonjmcghee wrote:
             | 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?
        
               | collaborative wrote:
               | Question.. is this using multiple threads?
               | 
               | If it isn't, how is this different than async operations?
        
               | remram wrote:
               | It is async, the operation is delayed until the processor
               | has nothing important to do.
        
               | remram wrote:
               | 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 wrote:
               | 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 wrote:
        
             | sheusndudn wrote:
        
             | Kiro wrote:
             | 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 wrote:
               | 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 wrote:
               | 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 wrote:
               | Can't reply above. So it's "low-priority" async?
        
         | eyelidlessness wrote:
         | 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.
        
       | brundolf wrote:
       | 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
        
       | pastelsky wrote:
       | 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
        
         | [deleted]
        
       | bombolo wrote:
       | I have an idea: why not speed up your site by NOT running js at
       | all?
        
         | balls187 wrote:
         | 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.
        
         | newbieuser wrote:
         | 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 wrote:
           | 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.
        
           | togaen wrote:
           | Totally agree with this, actually.
        
           | RunSet wrote:
           | This but unironically.
        
           | wonnage wrote:
           | Incoming flood of edgelord comments saying they think that
           | would be better
        
             | newbieuser wrote:
             | I made this comment to summon them. they come out of their
             | caves when they see something about no js lol
        
           | dahfizz wrote:
           | The web was a much better place 10 years ago.
        
         | onion2k wrote:
         | But then my contact form won't work!
         | 
         |  _ducks_
        
         | [deleted]
        
         | SketchySeaBeast wrote:
         | But what if we want a site that's more interactive than a blog?
        
           | MichaelCollins wrote:
           | 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 wrote:
             | 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".
        
         | pvg wrote:
         | That's a fine personal choice but don't snarkpoop on other
         | people's Show HN's.
         | 
         | https://news.ycombinator.com/showhn.html
        
       | qwery wrote:
       | 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.
        
         | [deleted]
        
         | madeofpalk wrote:
         | 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).
        
         | [deleted]
        
       | [deleted]
        
       | jasonjmcghee wrote:
       | 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"
        
       | simonpure wrote:
       | 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 wrote:
         | It's always Safari. I never figured out why.
        
           | naet wrote:
           | 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 wrote:
             | > 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.
        
         | CharlesW wrote:
         | > _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.
        
       | kitsunesoba wrote:
       | 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 wrote:
         | This is for site performance and not for general OS
         | performance.
        
           | Xelynega wrote:
           | "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 wrote:
             | 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.
        
       | Cloudef wrote:
       | 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.
        
         | k__ wrote:
         | Lol, thanks.
         | 
         | This comment was better than the docs, as usual.
        
         | balls187 wrote:
         | 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...
        
       | mfbx9da4 wrote:
       | Or... use a web worker
        
         | balls187 wrote:
         | 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.
        
       | nmcfarl wrote:
       | 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 wrote:
         | 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.
        
       | nottorp wrote:
       | One of the extensions that suspends idle tabs can protect me from
       | this?
        
         | toqy wrote:
         | 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.
        
           | bombolo wrote:
           | When there is nothing happening on my page my cpu can go
           | idle.
        
           | nottorp wrote:
           | You mean my browser still doesn't use enough CPU? I don't
           | want sites that aren't in focus to do anything.
        
             | MichaelCollins wrote:
             | Every web dev seems to think that their site specifically
             | is the reason everybody in the world bought a computer.
        
             | ovao wrote:
             | 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.
        
             | matsemann wrote:
             | 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 wrote:
               | 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.
        
               | Kiro wrote:
               | 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).
        
               | neweroldguy wrote:
               | This is just a generic "old man shouting at clouds"
               | complaint at this point. You're not engaging with the
               | material at all.
        
           | SketchySeaBeast wrote:
           | A bit of remote browser crypto mining?
        
         | travisd wrote:
         | 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...
        
       | Kiro wrote:
       | 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.
        
       | wonnage wrote:
       | 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.
        
       | butz wrote:
       | 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?
        
       | Eduard wrote:
       | The logo made me think it's called "oldle Task"
        
       | boredumb wrote:
       | 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.
        
       | codedokode wrote:
       | 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 wrote:
         | 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.
        
       ___________________________________________________________________
       (page generated 2022-11-24 23:01 UTC)