Offscreen documents within or outside of Service Workers - javascript

By doing something such as opening an offscreen document for audio playback:
function offscreenCreate()
{
chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: ['AUDIO_PLAYBACK'],
justification: "something"
});
}
I've seen a lot of documentation and such, showcasing the operation (and other operations related to offscreen documents, such as closing them) being used within Service Workers, but are there any significant differences in putting these operations within a Service Worker Vs. outside of a Service Worker (just a regular JS file), such as performance? More specifically, is it necessary in general?

The purpose of an offscreen document is to do something without showing a UI page to the user, but you may want to use it even from a visible UI page such as the popup because the lifetime of an offscreen document is tied to its internal affairs and not to the environment in which it was created e.g. when playing an audio, the document lives as long as it's playing the audio and terminated after 30 seconds of silence. Currently only the audio is limited, i.e. the lifetime is unlimited otherwise, but it'll likely change in the future because ManifestV3 intentionally removes persistence as much as possible and switches to event-driven on-demand logic, hence the controversial decision to use service workers.
There's no performance gain generally, rather there's a loss as it's a standard JS environment that consumes at least ~15MB of memory for JS engine + JS built-ins and at least 50ms of heavy CPU usage to initialize all that. However, using an offscreen document may help reduce resource usage and thus improve performance if you reduce the number of times the service worker restarts.

Related

Tasks for Animation Frames in a Browser

So I understand that in order to maintain the standard 60 frames per second when running animations in a web browser, we only get around 16ms per frame to perform any task we want to. The browser has to typically go through all the steps of the rendering pipeline to render each frame:
However, experts like Paul Lewis say that we realistically have only 10ms every frame to complete our tasks as browser has some 'overheads' and 'housekeeping' to do for every frame. I would like to know what these 'overheads' and 'housekeeping' tasks actually are?
"Overheads" vary per browser, and most don't occur on "every frame," but it all adds up, and overhead tasks performed either by your browser or by common client-side third-party code like Google Analytics also takes up valuable milliseconds. Common overhead tasks include:
Garbage collection
Listening for and handling often-repeated events such as scroll, mousemove, and some touch events (e.g. if you have analytics libs that generate heatmaps, that software may be tracking every mouse operation and touch operation)
Animations on your page (CSS ones or JavaScript-manages ones) which are "overhead" as far as the operation of your page are concerned
Third-party (or your own) code which does its thing only after certain conditions are met (e.g. lazy-loading of images, where images are loaded (and painted and composited) only when onscreen or close to being onscreen
Ads served by ad networks
Your own asynchronous code (triggered by setTimeout(), setInterval(), event-handlers, etc. etc. etc.) and that of any third-party libs which executes at some point, and when it does, eats into your 16ms (obviously there's a lot of overlap between this and the previous point)
Ad blockers and similar plugins (these run on a different thread, but interact with your thread, e.g., whenever DOM manipulation is necessary or any other cross-thread communication)
Loading of streaming media (which often consists of many network requests behind the scenes), which can include even relatively short, static videos
The overhead of running GIF animations or video (yours or UGC) - which is separate from the previous item, which concerns just the network interaction)
The repainting that needs to occur whenever the user scrolls or jumps to another part of your page (independent of any listeners for scroll, resize, etc.)
The potential complete redrawing of the DOM if some types of elements are added, removed, or resized, by you or by the user
Handling XHR or Iframe server responses or other data incoming from the network (like websockets traffic)
Tracking pixels (loading them, handling their demands of valuable JavaScript engine time); note that large sites often have a dozen or two tracking pixels of different types on them, and all it takes is one poorly written one to make huge demands on your browser's limited resources)
logic which attempts to anticipate what will happen next, and performing the optimizations involved
Heavy CPU usage by other applications running in your OS (or other pages running in other tabs in your browser) which take resources away from the JavaScript engine, rendering engine, etc.
Event-loop overhead - the JavaScript event loop is an elegant way of handling single-threaded code, but there's overhead involved in operating it
All of the above (a not-even-close-to-comprehensive list) would be considered "overhead" to whatever specific stuff you're trying to accomplish within 10ms or 16 ms or whatever.
Also note that some devices are just not capable of maintaining 60fps in-browser or anywhere; a slow CPU, lack of sufficient memory or persistent storace, etc., can slow all applications down, browsers included.
Maybe you're looking for something more specific, not sure - but I think I know the Paul Lewis thing you mention (where he talks about 10ms vs 16.66ms, etc.) and I'm not sure exactly what overhead he's talking about - but if, for example, you're trying to make one animation on a webpage run at 60fps, then all of the above would be "overhead" compared to your specific task of optimizing your animataion.
Hope this helps!

Engines in Browser - How do they interact?

I've been trying to learn more under the hood when it comes to Web Development, specifically JavaScript, and how the different engines interact with the JavaScript engine. For example, I know that the Rendering Engine is interacting, HTTP Requests, etc. I was just wondering, when the JavaScript Engine has to send data to another engine, such as the rendering engine, how much more computing has the JavaScript engine done by the time that data gets there?
The Web is a standardised platform running on the application layer of the Internet Protocol Suite.
It is a hypermedia system consisting of a protocol (HTTP), a markup language, a styling language (CSS) and a browser API (the Web API).
The Web was a development upon earlier hypermedia systems like HyperCard and uses a similar single-threaded, event-oriented rendering process.
The crux of your question is "how do the various parts of the browser interact to render a web page?"
The answer is a mixture of vendor-specific implementation and standardised behaviour defined by the standards bodies W3C and WHATWG.
The rendering process at a high level might be something like this:
The inbound message is exposed to the browser application by the operating system's networking substem (which in turn received the stream over the TCP IPS transport-layer) as a stream of bytes encoded using UTF-8.
Thus the networking subsystem of the browser receives an inbound UTF-8 encoded octet stream.
The browser will likely process the inbound stream of bytes on a thread or process other than that coordinating the rendering of the UI to avoid locking up the browser.
The browser understands the text-based HTTP protocol Tim Berners-Lee invented in 1989, and interprets the inbound bytes as an HTTP message.
The body of the message will correspond to the markup of the page. Once the page markup has been received it will be handed to a thread for rendering.
Starting at the top of the markup the browser rendering process will begin parsing according to an algorithm defined by the W3C/WHATWG.
When JavaScript is encountered, it will typically be run immediately, but there are complicated rules about exactly what happens when.
When references to resources (eg. images, scripts, stylesheets) are encountered, requests for their download will be made. Some will block the rendering process, some will not.
When a piece of JavaScript is encountered, its evaluation will usually block the user interface. This is because the Web was designed to have a single thread of execution controlling the rendering of a page, and JavaScript is part of that process. As far as I know, multi-threaded user interface rendering systems are unusual because of their complexity (although I could be wrong on this).
So the browser will extract the JavaScript from the markup (or a linked script resource), and hand it to the JavaScript engine for evaluation. The JavaScript runtime is an application that enables the evaluation of a stack-based language. It has a stack and a heap and logic for converting JavaScript script into a form understood by the CPU.
The stack has zero or more stack frames on it. In JavaScript stack frames are called execution contexts. An execution context is like a bookmark in a book, it helps the runtime keep track of where it is in the execution of the script. Only when the stack is empty of execution contexts can the browser continue with its rendering work - so yes, running JavaScript typically blocks rendering.
Communication between the various browser subsystems (network, JavaScript runtime, rendering) will occur via the heap allocated to the browser process, or if the browser is multi-process, by inter-process communication mechanisms exposed by the particular operating system being used (eg. named pipes).
Once enough (according to the W3C specification) of the markup (HTML) and styles (CSS) and enough of the script (JavaScript) has been evaluated, rendering can begin.
Rendering is a vendor-specific process, but most browsers will be similar at a high level. Each HTML element is processed in turn. Chrome uses the following sequence for every element on the page:
The JavaScript that applies to the element is evaluated.
The CSS styles that apply to the element are evaluated.
The element is laid-out on the page accordingly.
The element is painted into a bitmap (colored pixels).
The element is composited. It's final appearance it calculated according to the impact of the different layers of other elements on the page.
This process might be repeated more than once on any given element, depending on the contents of the page and changes introduced dynamically by scripts.
Computers are normally able to perform billions of calculations every second. However, the rendering thread only updates 60 times normally (refresh rate/VSync), and network requests are much slower. Offloading them to thread is cheaper compared to being blocked by waiting.
An additional reason to offload drawing is to make the interface look snappy: even if something is running long in the JS thread, an offloaded rendering thread will still be responsive as normal.
Very roughly, this is how it goes:
The browser gets the HTML page (or HTML data what was sent to it).
Browser begins to interpret and process the page
In the head section, if it sees any external linked files, such as JavaScript & CSS files, it initiates a load request immediately.
If there is any JavaScript, either in the HTML, or in a linked file, the JavaScript is executed immediately, unless it takes advantage of the newer async option. This is why JavaScript normally includes an event handler for when the document has finished loading.
The rest goes on …
Taking a break, note that the head stuff is processed as it is received, not later.
The body content is processed, from top to bottom.
While this is happening the DOM (Document Object Model — a sort of map of the contents) is created.
HTML visible content is rendered.
Any additional external data, such as images will initiate their own download requests. This content is loaded in parallel, rather than waiting. This is why badly designed HTML often leads to redrawing after images have been loaded.
The CSS, which is loaded by now, is applied at the same time.
That’s it for static content. There is one more stage, if you have JavaScript which changes content:
JavaScript can change the content of the Document at any time.
Often, but not always, changing the content can trigger a redraw. This will be needed if the change affects the layout.
JavaScript can also change individual CSS styles of HTML elements. Again, this may trigger a redraw.

How does multi-threading or async code in JavaScript work?

I am no beginner in javascript. I am actually working on this for past 3-4 months but today I read this statement about "What is JavaScript?"
JavaScript is single-threaded, non-blocking, asynchronous, concurrent language.
and I was lost. If JavaScript is single-threaded, how can it be concurrent and how can it be asynchronous because you need to keep track what your async code is doing and without another thread, it is impossible to track 2 or more code at a same time?
Ah.. here's the thing:
JavaScript is single threaded, but it has a lot of spare time on its hands.
When it is waiting for something to load out off the network, or its waiting for something off disk or waiting for the OS to hand something back to it, it can run other code.
setTimeout(function() {
// Do something later.
}, 1000);
While it is waiting for that timeout to return an execute that code, it can run code from OTHER timeouts, or network calls or any other async code in the system. It only runs ONE block of code at a time, however, which is why we say it is single threaded.
That thread can just bounce around. A lot.
And, as others have said, there are web workers and service workers, but those run VERY isolated from your main thread. They can't change values behind your main thread's back.
Updated per comment
The event loop works by:
Waiting for an event
Handling that event.
JavaScript is, indeed, blocked while handling an event. While code is running, nothing else in that page (assuming browser main thread) can run.
It isn't a literal event loop as you would have in C or C++, not as far as the JS is concerned. It's just events waiting to happen.
/// Sample code
document.addEventListener("click", function() { /* Handle click */ });
window.addEventListener("load", function() { /* handle load */ });
In this case, have two event listeners in our code. The JS engine will compile, then execute those two statements. Then, for all intents, "sleep" while waiting for something to happen. In reality, that same thread may handle various house-keeping tasks like drawing the HTML page, listening for move movements and emiting all sorts of events, but that doesn't matter for this discussion.
Then, once the rest of the page is loaded, the browser will emit a load event, which will be caught the listener and some more code will be run.
Then it will go back to idling until someone clicks on the document, then more code will run.
If we change the code to this:
document.addEventListener("click", function() {
while(true);
});
then when someone clicks on the document, our thread will go into an endless loop and all browser activity in that window will cease. Might even freeze the entire browser, depending in which one you are running.
Eventually, the browser will give a chance to kill that task so you can have your system back.
Latest Update
If you are aware of Webassembly there is a proposal in place for Threads via natively compiled modules
pthreads-style read this git issue tracker link(1073)
In continuation with #Jeremy J Starcher answer.
Javascript is always been single threaded runtime using asynchronous, non-blocking and event-driven models of execution.
To know more about event loop execution in JS i highly recommend you to watch this
Youtube video. Simply superb explanation by Philip Roberts.
Good olden days, developers would beat around the bush to achieve similar to thread model using
setTimeout with 0 - milliseconds or setIntervals : Basically instructing the engine to take up non-trivial tasks when the engine goes idle or wait mode during a http request or execute the code by switching back and forth in intervals kinda round-robin fashion.
Hidden Iframe : Run a JS code in a sandbox with a bridge to communicate from parent to iframe and vice versa. Technically Iframe doesn't run on separate thread but gets things done as a fake thread.
Fast forwarding [ >>> ] to Multi-threading models by ECMA:
Off late things have changed with the requirement to spawn a thread in JS engines to offload few smaller logical tasks or a network proxy task to a separate thread and concentrate on UI driven tasks like presentation and interaction layer on main thread, which makes sense.
With that requirement in mind ECMA came up with two model/API basically to solve this.
1. Web Worker: (SIC - Mozilla)
Web Workers makes it possible to run a script operation in background
thread separate from the main execution thread of a web application.
The advantage of this is that laborious processing can be performed in
a separate thread, allowing the main (usually the UI) thread to run
without being blocked/slowed down.
[ WebWorker can be split into two ]
Shared Worker
The SharedWorker interface represents a specific kind of worker that
can be accessed from several browsing contexts, such as several
windows, iframes or even workers. They implement an interface
different than dedicated workers and have a different global scope,
SharedWorkerGlobalScope.
Dedicated Worker : Same as Webworker, created using Worker() API but uses DedicatedWorkerGlobalScope
Worker is an object created using a constructor (e.g. Worker()) that
runs a named JavaScript file — this file contains the code that will
run in the worker thread; workers run in another global context that
is different from the current window. This context is represented by a
DedicatedWorkerGlobalScope object in the case of dedicated workers
2. Service Worker (SIC - Mozilla)
Service workers essentially act as proxy servers that sit between web
applications, and the browser and network (when available). They are
intended to (amongst other things) enable the creation of effective
offline experiences, intercepting network requests and taking
appropriate action based on whether the network is available and
updated assets reside on the server. They will also allow access to
push notifications and background sync APIs.
One example usage would be in PWA - Progressive web app to download scripts, lazy loading purposes of assets.
Read this article by Eric Bidelman on HTML5Rocks good explanation about the code itself and implementation
JavaScript may be "single-threaded" (I'm not sure this is really the case), but you can use/create webworkers to run javascript outside the main thread.
So you can run two pieces of code at the same time in parallel.
I think it is wrong to say that a language is this or that when what we really mean is that our programs are this or that.
For example: NodeJS is single-threaded and can run code asynchronous because it uses an event-driven behaviour. (Something comes up and fires an event... Node deals with it and if it is something like an online request, it does other things instead of waiting for the response... when the response comes, it fires an event and Node captures it and does whatever needs to be done).
So Javascript is...
single-threaded? No, as you can use WebWorkers as a second thread
non-blocking? You can write code that blocks the main thread. Just build a for that executes a hundred million times or don't use callbacks.
asynchronous? No, unless you use callbacks.
concurrent? Yes, if you use webworkers, callbacks or promises (which are really callbacks).

Caching text/image assets in performance-constrained environments

I'm working on an extremely performance-constrained devices. Because of the overhead of AJAX requests, I intend to aggressively cache text and image assets in the browser, but I need to configure the cache size per-device to as low as 1MB of text and 9MB of images -- quite a challenge for a multi-screen, graphical application.
Because the device easily hits the memory limit, I must be very cautious about how I manage my application's size: code file size, # of concurrent HTTP requests, # of JS processor cycles upon event dispatch, limiting CSS reflows, etc. My question today is how to develop a size-restrained cache for text assets and images.
For text, I've rolled my own cache using JSON.encode().length for objects and 'string'.length to approximate size. The application manually gets/sets cache entries. Upon hitting a configurable upper limit, the class garbage collects itself from gcLimit to gcTarget sizes, giving weight to the last-accessed properties (i.e., if something has been accessed recently, skip collecting that object the first time around).
For images, I intend to preload interface elements and let the browser deal with garbage collection itself by removing DOM elements and never persistently storing Image() objects. For preloading, I will probably roll my own again -- I have examples to imitate like FiNGAHOLiC's ImgPreloader and this. I need to keep in mind features like "download window size" and "max cache requests" to ensure I don't inadvertently overload the device.
This is a huge challenge working in such a constrained environment, and common frameworks like Backbone don't support "max Collection size". Elsewhere on SO, users quote limits of 5MB for HTML5 localStorage, but my goal is not session persistence, so I don't see the benefit.
I can't help feeling there might be better solutions. Ideas?
Edit: #Xotic750: Thanks for the nod to IndexedDB. Sadly, this app is a standard web page built on Opera/Presto. Even better, the platform offers no persistence. Rock and a hard place :-/.
localStorage and sessionStorage (DOM Storage) limits do not apply (or can be overridden) if the application is a browser extension (you don't mention what your application is).
localStorage is persistent
sessionStorage is sessional
Idea
Take a look at IndexedDB it is far more flexible though not as widely supported yet.
Also, some references to Chrome storage
Managing HTML5 Offline Storage
chrome.storage
With modern javascript engines cpu/gpu performance is not an issue for most apps (except games, heavy animation or flash) on even low powered devices so I suspect your primary issues are memory and io. Optimising for one typically harms the other but I suspect that the issues below will be your primary concern.
I'm not sure you have any control over the cache usage of the browser. You can limit the memory taken up by the javascript app using methods like those you've suggested but the browser will still do it's own thing and that is probably the primary issue in terms of memory. By creating your own caches you will probably be actually duplicating data that is already cached by the browser and so exacerbate the memory problem. The browser (unless you're using something obscure) will normally do a better job of caching than is possible in javascript. In any case, I would strongly recommend letting the browser take care of garbage collection as there is no way in javascript to actually force browsers to free up the memory (they do garbage collection when they want, not when you tell them to). Do you have control over which browser is used on the device? If you do, then changing that may be the best way to reduce memory usage (also can you limit the size of the browser cache?).
For ajax requests ensure you fully understand the difference between GET and POST as this has big implications for caching on the browser and on proxies routing messages around the web (and therefore also affects the logic of your app). See if you can minimise the number of requests by grouping them together (JSON helps here). It is normally latency rather than bandwidth that is the issue for AJAX requests (but don't go too far as most browsers can do several requests concurrently). Ensure you construct your ajax manager to allow prioritisation of requests (i.e stuff that affects what the user sees is prioritised over preloading which is prioritised over analytics - half the web has a google analytics call the first thing that happens after page load, even before ads and other content is loaded).
Beyond that, I would suggest that images are likely to be the primary contributor to memory issues (I doubt code size even registers but you should ensure code is minimised with e.g. google closure). Reduce image resolutions to the bare minimum and experiment with file formats (e.g. gif or png might be significantly smaller than jpeg for some images (cartoons, logos, icons) but much larger for others (photos, gradients).
10MB of cache in your app may sound small but it is actually enormous compared with most apps out there. The majority leave caching to the browser (which in any case will probably still cache the data whether you want it to or not).
You mention Image objects which suggests you are using the canvas. There is a noticeable speed improvement if you create a new canvas to store the image (after which you can discard the Image object). You can use this canvas as the source of any image data you later need to copy to a canvas and as no translation between data types is required this is much faster. Given canvas operations often happen many times a frame this can be a significant boost.
Final note - don't use frameworks / libraries that were developed with a desktop environment in mind. To optimise performance (whether speed or memory) you need to understand every line of code. Look at the source code of libraries (many have some very clever optimised code) but assume that, in general, you are a special case for which they are not optimised.

Parallel Processing Simulation in Javascript

I'm new to JavaScript so forgive me for being a n00b.
When there's intensive calculation required, it more than likely involves loops that are recursive or otherwise. Sometimes this may mean having am recursive loop that runs four functions and maybe each of those functions walks the entire DOM tree, read positions and do some math for collision detection or whatever.
While the first function is walking the DOM tree, the next one will have to wait its for the first one to finish, and so forth. Instead of doing this, why not launch those loops-within-loops separately, outside the programs, and act on their calculations in another loop that runs slower because it isn't doing those calculations itself?
Retarded or clever?
Thanks in advance!
Long-term computations are exactly what Web Workers are for. What you describe is the common pattern of producer and/or consumer threads. While you could do this using Web Workers, the synchronization overhead would likely trump any gains even on highly parallel systems.
JavaScript is not the ideal language for computationally demanding applications. Also, processing power of web browser machines can vary wildly (think a low-end smartphone vs. a 16core workstation). Therefore, consider calculating complex stuff on the server and sending the result to the client to display.
For your everyday web application, you should take a single-threaded approach and analyze performance once it becomes a problem. Heck, why not ask for help about your performance problem here?
JavaScript was never meant to do perform such computationally intensive tasks, and even though this is changing, the fact remains that JavaScript is inherently single-threaded. The recent web workers technology provides a limited form of multi-threading but these worker threads can't access the DOM directly; they can only send/receive messages to the main thread which can then access it on their behalf.
Currently, the only way to have real parallel processing in JS is to use Web Workers, but it is only supported by very recent browsers. And if your program requires such a thing, it could mean that you are not using the right tools (for example, walking the DOM tree is generally done by using DOM selectors like querySelectorAll).

Categories