1 of 38

State of Loading

2017 2018

KenjiBaheux@, Kinuko@ + team

BlinkOn 8

September 20-21st 2017

2 of 38

Goal of This Presentation

Make it righter

3 of 38

What is Loading?

4 of 38

Navigating

Loading

Interacting

Loading

L

L

Response

Animation

A

R

R

L

L

This is Loading

time

Launching

Startup

Navigating

Loading

...

Web platform viewpoint

5 of 38

When is Loading

Great?

6 of 38

With First Paint at 2s

With Meaningful Paint at 4s

Time To Consistently Interactive

User Happiness

1s

10s

2s

3s

4s

With First Paint at 2s

7 of 38

8 of 38

Loading’s Vanishing

Act

9 of 38

10 of 38

What to Focus on?

11 of 38

PWA & NBU

Progressive Web Apps

Naturally better user experiences

World Map of Internet Connected Devices (2012!)

Next Billion Users

Poor Loading user experience

because of slow/flaky networks

12 of 38

Well-Lit and Approachable Path

13 of 38

Problem Statement,

Achievements and Plan: 2017+

14 of 38

Loading today does not scale!�

Want to provide delightful loading experience for rich, modularized, progressive Web applications,

HOWEVER

Our bigger theme in 2017: Scalable Loading

15 of 38

  • Developer pain:
    • Lack of expressive primitives
    • Lack of native support for modularized Web apps
  • User pain:
    • Critical loading path is not super-optimized
    • Non-critical loading puts janks / disturbs other work
  • Our pain:
    • Inefficient, insecure, inflexible code with lots of debt :(

What’s Missing: 2017 Version

16 of 38

  • Fix Developer pain:
    • Provide expressive primitives: Fetch, Streams etc
    • Provide native support for ES6 Modules
  • Fix User pain:
    • Optimize critical path: PWA and Service Worker
    • Chunk work, throttle work, off-load from main thread
  • Fix Our pain:
    • Re-architecturing!

Our Focus in 2017

17 of 38

  • Fix Developer pain:
    • Provide expressive primitives: Fetch, Streams etc
    • Provide native support for ES6 Modules
  • Fix User pain:
    • Optimize critical path: PWA and Service Worker
    • Chunk work, throttle work, off-load from main thread
  • Fix Our pain:
    • Re-architecturing!

Our Focus in 2017

18 of 38

Expressive Primitives

  • What we shipped / shipping (since BlinkOn 7):
    • Streams: WritableStream and pipeTo()
    • <link rel=preload> for fetch()
    • CSS font-display
    • NetInfo API extension for Network Quality
    • fetch() with keepalive (Ongoing work)

19 of 38

  • Less latency, peak memory, jank�with streaming read/write and backpressure propagation

Streams API: How streams composition could work

Readable

Writable + Readable

Writable

pipeTo()

pipeTo()

async function fetchDirectlyIntoDOM() {� const response = await fetch('catnames', ...);� await response.body� .pipeThrough(new TextDecoder())� .pipeTo(targetDiv.writable);

}

This is just an example. Not yet Implemented

20 of 38

Expressive Primitives: What’s coming Next?

  • What is being discussed:
    • Priority Hints (aka “Fetch priority”: JS API, HTML attributes)
    • <lazyload> to lazily load frames/images
    • Batching requests (=> less battery usage)

We can’t work on many at once / want to work on what’s really needed, so your input is really appreciated!

21 of 38

ES6 Modules

  • What we shipped / shipping (since BlinkOn 7):
    • <script type=module> ← Yes, finally!
    • <script nomodule>
    • Modules support for Worklet

22 of 38

ES6 Modules: What’s coming Next?

  • Optimized graph fetching algorithm → will get faster!
  • <link rel=modulepreload>
  • Dynamic import()
  • Import.meta
  • integrity="" on <script type=module>
  • Modules for Workers

import("./optional-feature.js")� .then((m) => m.activate());

23 of 38

  • Fix Developer pain:
    • Provide expressive primitives: Fetch, Streams etc
    • Provide native support for ES6 Modules
  • Fix User pain:
    • Optimize critical path: PWA and Service Worker
    • Chunk work, throttle work, off-load from main thread
  • Fix Our pain:
    • Re-architecturing!

Our Focus in 2017

24 of 38

Service Worker Optimizations: Where’s the cost?

Major bottlenecks:

  • Startup: 250ms at 50%ile on Android (before optimization)
  • Main-thread contention: 100s of ms for startup / per fetch
  • Process hops: ~100 ms per fetch

Startup-cost hurts no-op Service Worker latency, which tends�to make developers hold off

25 of 38

Service Worker Optimizations

  • What we shipped / shipping (since BlinkOn 7):
    • Navigation Preload
    • Speculative startup from Omnibox
    • Off-main-thread Fetch

  • What’s in-progress:
    • Script Streaming
    • Re-architecturing for performance

Roadmap: bit.ly/2xaybOc

Come and listen to

horo@’s lightening talk

for more details!

26 of 38

Chunking and Yielding between Content Script runs

time

Before

Extension 1

Ext 2

3

4

Ext 5

User action

Response

User action

time

After

Extension 1

Ext 2

3

4

Ext 5

User action

Response

User action

content_script for all extensions used to run in one task [ JANK] �→ chunk it into multiple tasks asyncly!

27 of 38

Count

Duration of content script run (ms)

Before

After

# of content script runs leading to Jank

less Jank caused by extensions

~30%

Canary/Dev numbers

Beta experimenting starting

Chunking and Yielding between Content Script runs

28 of 38

Background Tab Throttling

From our in-lab local measurements (not from real world!):

Potential win for faster FMP and less OOM

if we throttle non-critical loading?

29 of 38

Background Tab Throttling

  • Throttle the loading activity in background tabs
    • For better user experience in multi-tab scenarios
      • Less OOM, less UX jank
    • For faster ttFMP on foreground tabs

  • Status:
    • Experimenting on Beta (waiting for more data)

30 of 38

  • Fix Developer pain:
    • Provide expressive primitives: Fetch, Streams etc
    • Provide native support for ES6 Modules
  • Fix User pain:
    • Optimize critical path: PWA and Service Worker
    • Chunk work, throttle work, off-load from main thread
  • Fix Our pain:
    • Re-architecturing!

Our Focus in 2017

31 of 38

Re-architecturing Loading Pipeline

  • Our Loading pipeline was designed when Chrome was born!
    • Was good, simple code initially :)

  • Lots of code debt
    • All loading goes through main-thread [JANK]
    • Security features are added a bit ad-hocly [CHAOS]
    • Dumb client, assumes monolithic browser [CAN’T S13N]
    • A lot of legacy glue code / hooks [NEEDS ONION SOUP]
    • Many things work at per-process [BAD ATTRIBUTION]

32 of 38

Re-architecturing Loading Pipeline

Shipped:

  • Mojo Loading (on Desktop), with 9%TTFCP improvement :)

In-progress & Planned:

  • Move CORS / CSP / MIX out of Blink
  • Migrate to Per-frame loader factory
  • No more RenderFrameImpl::WillSendRequest() hooks
  • All loading features (Blob, AppCache, SW) use Mojo Loading
  • Servicification! Onion Soup!

Scheduling optimization

+Mojo-loading

Time To First Contentful Paint (median)

Baseline

% faster

33 of 38

  • Single logic shared by various components�both inside/outside Blink
  • Live outside of renderer for flexibility
    • sendBeacon() and keepalive fetch()

Status:

Unified Web Security Logic (CORS / CSP / MIX)

CORS

CSP

MIX

Fetch

Background

Fetch

Navigation

Expect-CT

ServiceWorker

34 of 38

Re-architecturing Loading Pipeline

35 of 38

Done

  • Push cancellation (crbug/232040, crbug/727653).
  • Proper status code when rejecting push streams (crbug/726725).

(re)Considering

(talk to lassey@ or kenjibaheux@)

  • H2 connection reuse for non-credentials request (fetch/341).
  • Cache digest: looking for evidence of value.
  • Stale-while-revalidate: blocked on PlzNavigate, servicification, your input needed for prioritization!

HTTP/2

In progress

  • Correct request matching for pushed responses (i.e. Vary; crbug/554220)

36 of 38

From There...

37 of 38

  • A well lit and approachable Loading Path.

(e.g. Fetch Priority, Ways to take care of the hard things with Loading).

  • Loading additional code/data doesn’t jank the user experience.

  • Efficient loading with modularized resources.

(e.g. let you use ES6 modules as-is).

  • Navigating a Multi-Page-App feels like a Single-Page-App or a Native App.

Tentative Goals for 2018

38 of 38

Thank You