Profile cover photo
Profile photo
Vladimir Melnick
Ruby on Rails в сердце
Ruby on Rails в сердце

Vladimir's posts

Post has shared content

Post has attachment

Post has shared content
Just say no to reimplementing the browser's parser in JavaScript.

Here we have a library from Mobify ( that allows you to "capture" the HTML in the document before the browser parses it. You get a chance to manipulate the content to indicate which image assets should get loaded by the browser.

It's clear that there is a real problem in browsers today that the Mobify team is trying to solve: browsers do not understand which image assets are actually going to be needed for responsive pages, so they tend to try to download all of the assets, which is obviously wasteful and also harmful for performance.

But the solution provided here is actually much worse than just loading all the image assets. Here's what the capturing API does:

1. inject a plaintext tag very early in the document:
   // Prevent the browser from downloading website resources
   document.write('<plaintext style="display:none">');
The plaintext tag never closes so all HTML that comes after it is parsed as plain text. Essentially this is a way of turning off the browser's HTML parser (and lookahead parser!) from JavaScript.

2. load some external JavaScript libraries needed to perform the capturing operations and prioritize which resources should be loaded

3. once the capture code loads, parses, and executes, create a child HTMLDocument which is used to parse everything after the plaintext tag in a new document context

4. invoke a callback in the main application that manipulates the document to enable/disable certain DOM elements

5. once the child HTMLDocument manipulation is complete, replace the main document's contents with this modified child document's contents

6. now the browser finally gets a chance to render some content to the screen

On the one hand, this is really cool. You just implemented a smarter HTML parser that understands media queries in JavaScript. On the other hand, you just reimplemented part of the browser... in JavaScript.

Let's dig a little deeper into what this means from a page load performance perspective. How much delay have we introduced to rendering the page as a result of loading the document this way? If we assume a mobile network round trip of 250 milliseconds and that we are loading mobify from a CDN, that's 750ms (DNS, TCP, request/response) blocking time before the browser even receives the first byte of mobify. Then it has to parse and execute mobify which will be non-zero time on a mobile device (let''s say 100ms), then it has to parse the document's contents in the child document (let's say another 100ms), then it has to copy the modified document's contents back to the main document (let's say another 100ms). So far we're already up over 1 second.

But it's actually even worse than this. None of the mobify code can execute until the main HTML has been fully downloaded. If the HTML document is large-ish (say, 10s of kB compressed), we're looking at incurring multiple additional round trips due to TCP congestion window growth before we even begin executing the mobify code. Let's say we incur 2 window growth round trips, for an additional 500ms.

Once this is all done, the stylesheet after the plaintext tag can finally begin downloading. That'll incur another round trip or 2, maybe more if we have to grow the TCP congestion window while downloading it.

Once this is done, after 2+ seconds on a mobile network, the browser can finally start rendering some content to the screen. It's hard to look at this as a performance win.

By trying to re-implement part of the browser in JavaScript, we've eliminated the browser's ability to parse or render any real page content, serializing the real parser behind the download, parse, and execution of external mobify JavaScript resources. It's going to be really hard to make up for this by eliminating the download of images. Keep in mind that JavaScript and CSS are parser and renderer blocking, whereas image assets do not block the parser or the renderer. Downloading more parser blocking resources in exchange for fewer non-blocking resources is very unlikely to be a performance win.

I am glad that the Mobify team is trying to improve responsive image efficiency, but solutions like this really need to live in the browser. The browser has so much more insight into the state of the document via its lookahead downloader, its ability to parse and render HTML in a streaming fashion, etc. It also doesn't have to download its parser from a web server (obviously), so none of those network delays are incurred by the browser's parser.

When you discover a shortcoming in the way web browsers parse your pages, rather than trying to implement a smarter browser in JavaScript, instead work on making the browsers themselves smarter. Open bugs with the browser vendors (or submit patches!), explain the problems you are encountering, and help the browser developers to understand what they need to do to make your pages load more efficiently.

Just say no to reimplementing the browser in JavaScript.

Update: to demonstrate the performance cost of using this solution on a high-latency (e.g. mobile) connection, here are two example pages, one that includes a single image, and another that includes the same image but loads the Mobify capture framework first. This isn't a real responsive page; the point of this demo is to show how much delay is added to fetching any of the assets on your page when you use Mobify capture.

First, the simple page:

And now the same page loading Mobify capture first:

Now, webpagetest results for each, using Chrome desktop on a high latency network (250ms round trip):
Simple page (without Mobify capture):
the image asset starts downloading at 810ms.

And the page with Mobify Capture:
the image asset starts downloading at 2.57 seconds.

So we see that there is a roughly 1.75 second latency penalty as a result of using Mobify capture for this network configuration.

Post has shared content
All the world’s major religions, with their emphasis on love, compassion, patience, tolerance, and forgiveness can and do promote inner values. But the reality of the world today is that grounding ethics in religion is no longer adequate. This is why I am increasingly convinced that the time has come to find a way of thinking about spirituality and ethics beyond religion altogether.

Post has attachment

Post has attachment

Post has attachment

Post has attachment

Post has attachment

Post has attachment
Wait while more posts are being loaded