Intent to Implement: NavigationController

834 views
Skip to first unread message

Alec Flett

unread,
Jul 30, 2013, 4:45:58 PM7/30/13
to blink-dev


Contact emails

alec...@chromium.org, mich...@chromium.org, sligh...@chromium.org


Spec

There is no official spec yet, but instead an "explainer":

https://github.com/slightlyoff/NavigationController/blob/master/explainer.md

https://github.com/slightlyoff/NavigationController/blob/master/advanced_topics.md


This "explainer" was initially put together by Alex Russell, and further refined in discussions with Mozilla (Jonas Sicking and others) and other googlers, thanked at the bottom of the explainer.


Summary

At its core, NavigationController is a scriptable caching proxy that sits between a web page and the network.

There are two fundamental parts to NavigationController: 
1. A shared worker-like thread that intercepts some/all resource requests for a given page that matches a developer-chosen pattern.
2. A programmable HTTP cache that can be updated atomically.

These APIs are complementary such that it is easy for the developer to deliver a specific resource from the cache given a specific request. However, being able to intercept the requests before the cache is involved gives the developer great freedom in delivering or even generating resources.


Motivation

The larger goal is to fix the offline web by replacing AppCache as a way of storing and delivering resources according to the needs of the developer, rather than the (in hindsight) poorly-anticipated needs that drove AppCache.


Compatibility Risk

This is a new API and Mozilla has recently issued their own Intent to Implement for this feature. As the spec isn't written, there's obvious risks of divergence in implementation behavior, but implementation will be informing the spec there. 


Ongoing technical constraints

The implementation relies heavily on Promises, and as such will require them to ship. In addition, the implementation will be leaning heavily on existing worker and cache infrastructure and so may need to introduce new abstractions to them to support new use cases.


Blink side changes will mostly be around workers and add additional bindings and events to support the API. Much of the heavy lifting around resource delivery and install/upgrade will be implemented on the chromium side.


Will this feature be supported on all five Blink platforms (Windows, Mac, Linux, Chrome OS and Android)?

Yes


OWP launch tracking bug?

Not yet.

Row on feature dashboard?

Not yet, we should create one. 


Requesting approval to ship?

No.



Kenneth Rohde Christiansen

unread,
Jul 30, 2013, 4:51:16 PM7/30/13
to Alec Flett, blink-dev
I am a big fan of this, so I would like very much to see this move
forward. Implementing it would be a good first step so lgtm from here.

Great to hear that Mozilla is looking into implementing this as well

Cheers
Kenneth
--
Kenneth Rohde Christiansen
Senior Engineer, WebKit, Qt, EFL
Phone +45 4294 9458 / E-mail kenneth at webkit.org

﹆﹆﹆

Ehsan Akhgari

unread,
Jul 30, 2013, 4:52:10 PM7/30/13
to Kenneth Rohde Christiansen, Alec Flett, blink-dev
I'm the person who is planning to implement this in Gecko, and I look forward to working with you guys to improve things as we make progress!  :-)

Cheers,

Michael Nordman

unread,
Jul 30, 2013, 9:29:38 PM7/30/13
to Ehsan Akhgari, Kenneth Rohde Christiansen, Alec Flett, blink-dev
Fantastic to hear about the development in Gecko'land too!

sh...@mobify.me

unread,
Aug 14, 2013, 11:36:29 AM8/14/13
to blin...@chromium.org, alec...@google.com
Just found this, and it seems extremely interesting and has lots of potential to be a very useful addition to browsers. I was disappointed to read this bit though:

"The first time http://videos.example.com/index.html is loaded, all the resources it requests will come from the network. That means that even if the browser runs the install snippet for ctrl.js, fetches it, and finishes installing it before it begins fetching logo.png, the new controller script won't be consulted about loading logo.png. This is down to the first rule of Navigation Controllers"

I think there is a lot of value that can come from giving developers the power to have full control over resource loading, even on the first load. For example, having the ability to swap image URLs before they are kicked off by the preloader would be a big win for responsive images. I am the author of the Capturing API (https://hacks.mozilla.org/2013/03/capturing-improving-performance-of-the-adaptive-web/) which provides this exact functionality in a non-optimal way. In order to control resource loading with Capturing, we must first buffer the entire document before being able to manipulate resources, which is a bummer, but it's ability to control resources on the page is very, very useful. If the Navigation Controller worked on first page load, the need for Capturing would be eliminated. 

It does not seem like total control of resource loading is the goal of the Navigation Controller, but the API is very close to being able to provide exactly that without much change at all. I would love to have a conversation about whether or not adding this functionality is feasible!

Alec Flett

unread,
Aug 14, 2013, 12:09:16 PM8/14/13
to sh...@mobify.com, blink-dev
So this is a spec issue not a blink-specific issue... you can file an issue at https://github.com/slightlyoff/NavigationController/ until we get this moved further along - this is something we discussed but it's a surprisingly hard issue to deal with.

Alec

sh...@mobify.me

unread,
Aug 14, 2013, 1:35:17 PM8/14/13
to blin...@chromium.org, alec...@google.com
Thanks Alec, will do.


On Tuesday, 30 July 2013 13:45:58 UTC-7, Alec Flett wrote:

William Chan (陈智昌)

unread,
Aug 15, 2013, 1:47:58 AM8/15/13
to Alec Flett, blink-dev
Overall I'm very excited about NavigationController. I'm not going to bother talking about all the awesome stuff I like about it (unless you really want me to). Instead, I'm going to voice my performance concerns so that people are aware of them. Chromium/Blink goes through a lot of effort in the resource loading pipeline to minimize resource fetching latency, and this API has the potential to incur a web worker thread hop roundtrip + JS execution on every single resource request, which has rather large performance implications, especially on mobile devices, where the thread hop roundtrip latency and the CPU time for JS execution will add a significant amount of latency until network IO can even be started. What I can kinda imagine happening is that libraries get built on top of NavigationController that want full control, so they hook all resource requests by default, even if they only care about specific URIs. I think it would be unfortunate if this becomes a common mode of operation, since web developers using said libraries may not realize this harm.

As stated earlier, despite my perf concerns, I'm overall still very excited about NavigationController. Just wanted to call attention to some performance issues in case they weren't obvious to folks. Cheers.


On Tue, Jul 30, 2013 at 10:45 PM, Alec Flett <alec...@google.com> wrote:

Alec Flett

unread,
Aug 15, 2013, 4:13:58 PM8/15/13
to William Chan (陈智昌), blink-dev

Yep, you're not the only one who says "cool! Wait..what about performance?"

The simple response is that NC allows you to skip the network entirely when possible - meaning that even a little bit of slow JS can be faster than downloading a 50k image over a cell connection. It allows things like

1) Making decisions about cache policy that are app-specific and not expressible in HTTP headers. 

For example, if a user does something that modifies a particular object on the server, often from JS you know which pages are instantly stale, at least from the perspective of the individual user who made the change... but the only way to handle this with HTTP today is to make sure, in advance, that those pages are short-lived, so the browser is forced to go hit the server again and get a fresh copy.

2) Prefetching stuff out-of-band. 

For example, sometimes you know in advance, which resources are going to be needed for a particular workflow - for instance a set of images that are shared from steps 4 to 12 of a 14 step data entry task. You can begin fetching them explicitly so that when you get to page 4 the image is already ready. Today you might do that by trying creating Image() tags and hoping like hell that the image load isn't interrupted by page navigation.

3) Efficient in-browser page templating

When your app is written in a way where you're mostly serving static html and JSON, and rendering in the browser, you can deliver pages that are pre-rendered to the browser, possibly even assembling pages from shared fragments the way server-side templating systems do. In a way that maintains URLs. Today you'd do in-DOM manipulation during pageload (where it's tricky to avoid layouts + paints)

You can mimic *some* of these workarounds using things like SharedWorkers and AppCache today, and there have been attempts (pre fetching/rendering, etc) by browsers to anticipate needs like these, but at some point a trap door like NC can give developers immense control in a way that is specific to their app, that we could never really anticipate.

The key thing is that we're allowing the developer to weigh the balance of local CPU vs network latency in situations where the app knows better than the browser what requires a network connection or not.

Alec

William Chan (陈智昌)

unread,
Aug 15, 2013, 4:42:21 PM8/15/13
to Alec Flett, blink-dev
On Thu, Aug 15, 2013 at 10:13 PM, Alec Flett <alec...@google.com> wrote:

Yep, you're not the only one who says "cool! Wait..what about performance?"

The simple response is that NC allows you to skip the network entirely when possible - meaning that even a little bit of slow JS can be faster than downloading a 50k image over a cell connection. It allows things like

1) Making decisions about cache policy that are app-specific and not expressible in HTTP headers. 

For example, if a user does something that modifies a particular object on the server, often from JS you know which pages are instantly stale, at least from the perspective of the individual user who made the change... but the only way to handle this with HTTP today is to make sure, in advance, that those pages are short-lived, so the browser is forced to go hit the server again and get a fresh copy.

2) Prefetching stuff out-of-band. 

For example, sometimes you know in advance, which resources are going to be needed for a particular workflow - for instance a set of images that are shared from steps 4 to 12 of a 14 step data entry task. You can begin fetching them explicitly so that when you get to page 4 the image is already ready. Today you might do that by trying creating Image() tags and hoping like hell that the image load isn't interrupted by page navigation.

Would love to hear more details about this and how it compares to existing solutions like link rel=prefetch. I can imagine the differences, but I'd like to hear your thoughts on how NavigationController compares.
 

3) Efficient in-browser page templating

When your app is written in a way where you're mostly serving static html and JSON, and rendering in the browser, you can deliver pages that are pre-rendered to the browser, possibly even assembling pages from shared fragments the way server-side templating systems do. In a way that maintains URLs. Today you'd do in-DOM manipulation during pageload (where it's tricky to avoid layouts + paints)

You can mimic *some* of these workarounds using things like SharedWorkers and AppCache today, and there have been attempts (pre fetching/rendering, etc) by browsers to anticipate needs like these, but at some point a trap door like NC can give developers immense control in a way that is specific to their app, that we could never really anticipate.

The key thing is that we're allowing the developer to weigh the balance of local CPU vs network latency in situations where the app knows better than the browser what requires a network connection or not.

Yep, you're hitting many of the possible uses for NavigationController which lead me to remain overall very excited about it. But as I tried to highlight before, the simple act of using NavigationController in order to gain control within the web app over resource fetches, so that the developer can weigh said balance, will itself lead to a perf cost. So if you register a NavigationController for "/*", then you're going to pay that cost for all resource fetches on that origin, even if the controller just forwards all resource fetches onword to the resource loader. Now, if you do smart things like what you've mentioned, then the perf gains of those techniques will almost assuredly outweigh the perf cost I mention. But if you just register a NavigationController for "/*", but don't leverage the power, then you non-obviously get perf degradation on all resource fetches for that origin. So what worries me is someone creating a framework on top of NavigationController that always registers a controller for "/*", and then creates a framework-specific registration system.

Ilya Grigorik

unread,
Aug 15, 2013, 5:01:48 PM8/15/13
to William Chan (陈智昌), Alec Flett, blink-dev

On Thu, Aug 15, 2013 at 11:42 PM, William Chan (陈智昌) <will...@chromium.org> wrote:
2) Prefetching stuff out-of-band. 

For example, sometimes you know in advance, which resources are going to be needed for a particular workflow - for instance a set of images that are shared from steps 4 to 12 of a 14 step data entry task. You can begin fetching them explicitly so that when you get to page 4 the image is already ready. Today you might do that by trying creating Image() tags and hoping like hell that the image load isn't interrupted by page navigation.

Would love to hear more details about this and how it compares to existing solutions like link rel=prefetch. I can imagine the differences, but I'd like to hear your thoughts on how NavigationController compares.

Correct me if I'm wrong, but #2 is perfectly achievable even without rel=prefetch. Any app can trigger a bunch of XHR's and preload those assets into cache for future navigation. rel=prefetch just makes this even simpler by providing a one line declarative attribute/element.

Similarly, templating (#3) seems like more of a concern for web components, not nav controller?

I'm in the same boat as Will -- sounds awesome, but seems like there is a huge performance question mark here...

ig

sh...@mobify.me

unread,
Aug 15, 2013, 5:39:28 PM8/15/13
to blin...@chromium.org, alec...@google.com
So, while there are performance implications of giving developers full control of resource loading, I really think it's the best solution going forward. One thing we all have to stop and realize is that when developers want to control resources, they manage to do it - just in non-optimal ways that also have big performance implications. One solution developers have and use is proxying pages and making modifications to resources before hitting the client, which can have big security implications, and does not have the advantage of making decisions based on device conditions. Another option developers have and use is writing alternates to `src` and `href` (such as `data-src` and `data-href`) and loading them after the DOM content is loaded, thus needing to wait for rendering to complete before loading resources. Another option is Mobify's Capturing API, which also blocks page rendering.

So when thinking about giving the Navigation Controller the power to control resources on first load, its not a matter of blocking vs no blocking, its a matter of blocking vs the 3 options previously listed.


On Tuesday, 30 July 2013 13:45:58 UTC-7, Alec Flett wrote:
Message has been deleted

Chris Bentzel

unread,
Aug 21, 2013, 12:20:16 AM8/21/13
to Ilya Grigorik, Alec Flett, blink-dev, sh...@mobify.me

My primary concern for now is to make sure that the cost of checking whether a URL has an associated controller is minimal - in particular for all of the URLs which exist now and do not have a controller associated with it. Sites which don't use the feature shouldn't pay for it.

We have experienced slowdowns in the past on Chrome for JS eval in the critical path of network requests (PAC eval, WebRequest extensions) particularly when there are a huge flurry of requests at page load. It looks like you can run multiple instances of a controller at once which may help, but I don't know if IndexedDB or the new Cache object end up acting as a bottleneck in that case due to serialization requirements.

On Aug 16, 2013 7:16 PM, <igri...@google.com> wrote:


On Friday, August 16, 2013 12:39:28 AM UTC+3, sh...@mobify.me wrote:
So, while there are performance implications of giving developers full control of resource loading, I really think it's the best solution going forward. One thing we all have to stop and realize is that when developers want to control resources, they manage to do it - just in non-optimal ways that also have big performance implications. One solution developers have and use is proxying pages and making modifications to resources before hitting the client, which can have big security implications, and does not have the advantage of making decisions based on device conditions. Another option developers have and use is writing alternates to `src` and `href` (such as `data-src` and `data-href`) and loading them after the DOM content is loaded, thus needing to wait for rendering to complete before loading resources. Another option is Mobify's Capturing API, which also blocks page rendering.

So when thinking about giving the Navigation Controller the power to control resources on first load, its not a matter of blocking vs no blocking, its a matter of blocking vs the 3 options previously listed.

Those who are willing to accept sub-optimal performance "manage to do it" - yes. Responsive images (which is what you're hinting at), should be resolved via appropriate browser API's (srcset, picture, client-hints, etc). The best option, that is missing from your list, is "the browser does the right thing and does it without blocking the network or rendering stacks".

ig

Tom Wiltzius

unread,
Aug 22, 2013, 2:40:30 PM8/22/13
to Chris Bentzel, Ilya Grigorik, Alec Flett, blink-dev, sh...@mobify.me
On Tue, Aug 20, 2013 at 9:20 PM, Chris Bentzel <cben...@chromium.org> wrote:

My primary concern for now is to make sure that the cost of checking whether a URL has an associated controller is minimal - in particular for all of the URLs which exist now and do not have a controller associated with it. Sites which don't use the feature shouldn't pay for it.

This should be very achievable; this decision could be moved fairly far up so outgoing requests can theoretically take totally different paths based on whether the associated document has a controller registered or not (i.e. one branch on one piece of document state is all that's necessarily incurred for documents without controllers attached).

Alec Flett

unread,
Aug 22, 2013, 2:55:37 PM8/22/13
to Tom Wiltzius, Chris Bentzel, Ilya Grigorik, blink-dev, sh...@mobify.me
On Thu, Aug 22, 2013 at 11:40 AM, Tom Wiltzius <wilt...@chromium.org> wrote:



On Tue, Aug 20, 2013 at 9:20 PM, Chris Bentzel <cben...@chromium.org> wrote:

My primary concern for now is to make sure that the cost of checking whether a URL has an associated controller is minimal - in particular for all of the URLs which exist now and do not have a controller associated with it. Sites which don't use the feature shouldn't pay for it.

Yes, of course! In particular, this already exists for appcache - the matching is via a url pattern - there's no reason for JS to get involved at all.

In particular appcache has a very similar matching mechanism, and appcache doesn't even involve JS.
 
This should be very achievable; this decision could be moved fairly far up so outgoing requests can theoretically take totally different paths based on whether the associated document has a controller registered or not (i.e. one branch on one piece of document state is all that's necessarily incurred for documents without controllers attached).
 

a key bit of this is that the toplevel *document* has to match the url pattern, and from then on, all resources loaded from that document context are "owned" by the navigation controller. So really the url matching is done just once per document load.

Alec


Chris Bentzel

unread,
Aug 30, 2013, 11:09:27 AM8/30/13
to Alec Flett, Tom Wiltzius, Ilya Grigorik, blink-dev, Shawn Jansepar
On Thu, Aug 22, 2013 at 2:55 PM, Alec Flett <alec...@google.com> wrote:
>
>
>
> On Thu, Aug 22, 2013 at 11:40 AM, Tom Wiltzius <wilt...@chromium.org>
> wrote:
>>
>>
>>
>>
>> On Tue, Aug 20, 2013 at 9:20 PM, Chris Bentzel <cben...@chromium.org>
>> wrote:
>>>
>>> My primary concern for now is to make sure that the cost of checking
>>> whether a URL has an associated controller is minimal - in particular for
>>> all of the URLs which exist now and do not have a controller associated with
>>> it. Sites which don't use the feature shouldn't pay for it.
>
> Yes, of course! In particular, this already exists for appcache - the
> matching is via a url pattern - there's no reason for JS to get involved at
> all.
>
> In particular appcache has a very similar matching mechanism, and appcache
> doesn't even involve JS.

Agreed that it could be similar to appcache's matching mechanism.

Note that there is a slight delay for top-level requests due to this
appcache check, though.

Ultimately at some point we'll need to access persistent storage to
see if a controller exists - it could just be paged in at startup so
might impact startup latency, or it could be demand-based and impact
steady-state navigation latency.

From UMA it looks like the impact of this for AppCache is mostly
small, but I wanted to raise it as a potential concern as it will add
yet another preflight check for many network requests.

Alec Flett

unread,
Aug 30, 2013, 12:27:35 PM8/30/13
to Chris Bentzel, Tom Wiltzius, Ilya Grigorik, blink-dev, Shawn Jansepar
Just for my own edification, do you have a link to the appcache UMA stats you're talking about? I'd like to make sure we instrument this similarly, but I'm also interested in the raw numbers for helping to make design decisions around this.

Alec

Max Heinritz

unread,
Apr 17, 2014, 3:13:53 PM4/17/14
to Alec Flett, Chris Bentzel, Tom Wiltzius, Ilya Grigorik, blink-dev, Shawn Jansepar
FYI, here's a new launch tracking bug for this feature, now called ServiceWorker: http://crbug.com/364627
Reply all
Reply to author
Forward
0 new messages