Introduction to
Performance APIs
Chrome Tech Talk Night #12
Shogo Sensui (@1000ch)
Shogo Sensui
(@1000ch)
Software Engineer
Merpay, Inc / Mercari, Inc
Table of contents
● Lazy Loading
● Prefetch
● Off The Main Thread
🐢 Lazy Loading
Intersection Observer
> The Intersection Observer API
provides a way to asynchronously
observe changes in the intersection
of a target element with an
ancestor element or with a
top-level document's viewport.
const observer = new
IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
console.log(entry);
}
}
});
const el = document.querySelector('#el);
observer.observe(el);
WebKit shipped!!!
Intersection Observer v2
Intersection Observer v2 will detect
the actual visiblity (like “opacity”).
● New options
○ trackVisiblity constructor
option to track visiblity
○ isVisible property in
IntersectionObserverEntry
● IntersectionObserver v2 demo
const el = document.querySelector('#el);
const observer = new
IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isVisible) {
console.log(entry);
}
}
});
observer.observe(el, {
trackVisiblity: true
});
Browser native lazy-loading
lazyload attribute to load if
display with-in viewport.
● will be enabled on...
○ <img>
○ <iframe>
● Lazyload images and iframes
by bengreenstein · Pull Request
#3752 · whatwg/html.
● Blink LazyLoad Design Docs
(public)
<img
src="https://example.com/image.jpg"
lazyload="on">
<iframe
src="https://google.com"
lazyload="on">
</iframe>
⚡ Prefetch
Priority Hints for resource loading
importance attribute to indicate
resource priority.
● will be enabled on...
○ <img>
○ <iframe>
○ <script>
○ <link>
○ fetch()
● Priority Hints Draft Community
Group Report 18 October 2018
<img
src="https://example.com/image.jpg"
importance="high">
<iframe
src="https://example.com"
importance="low">
</iframe>
<script>
fetch('https://google.com', {
importance: 'high'
});
</script>
Resource Hints
Resource Hints provides
speculative loading which consists
of...
● DNS Prefetch: host
● Preconnect: host
● Prefetch: resources
● Prerender: specified page
<link rel="dns-prefetch" href="//example.com/">
<link rel="preconnect" href="//example.com/">
<link
rel="prefetch" as="image"
href="https://example.com/high-priority.jpg">
<link
rel="prerender"
href="https://example.com/">
https://www.igvita.com/2015/08/17/eliminating-roundtrips-with-preconnect/
Preload
Preload provides aggressive loading
● For nested resources for initial
loading
○ e.g) Images referred in CSS
○ e.g) JavaScript loaded on JavaScript
● Similar to Resource Hints
<link
rel="preload"
href="https://example.com/high-priority.jpg">
<link
rel="preload"
href="https://example.com/high-priority.js">
Chrome Prerender History
chrome://net-internals/#prerender
GoogleChromeLabs/quicklink
> Faster subsequent page-loads by
prefetching in-viewport links during
idle time
Speculative prefetch links with-in
viewport using following APIs.
● Intersection Observer
● Prefetch (Resource Hints)
● requestIdleCallback()
● Network Information API.
quicklink({
ignores: [
//api/?/,
uri => uri.includes('.zip'),
(uri, el) => el.hasAttribute('noprefetch')
]
});
Nuxt v2.4 supports prefetching links in viewport
> Nuxt.js will automagically
prefetch the code-splitted pages
linked with <nuxt-link> when visible
in the viewport by default. This
hugely improves the end user
performances, inspired by
quicklink.
AMP is the best example for Prefetch/Prerender
AMP prefetch/prerender some resources to achieve instant loading
● Prefetch resources
○ from Google AMP Cache hosted on Google
● Prerender documents
○ AMP’s prerender differs from <link rel=preload>
■ Why AMP HTML does not take full advantage of the preload scanner
AMP’s URL is a long-standing problem..
Web Packaging will solve the AMP’s URL problem
Web Packaging consists of...
● Signed HTTP Exchanges: Signs request/response including URL with
private keys and creates .sxg file
● Bundled HTTP Exchanges: Bundles subresources in response
● Loading Signed Exchanges: Loads signed .sxg file and displays the
original URL instead of distributed URL
🚀 Off The Main Thread
More rich,
More heavy.
Web Page’s payload is increasing continuously
Main Thread is busy
● Loading (almost described by Critical Rendering Path)
○ Fetch HTML
○ Parse HTML and construct DOM
○ Fetch sub-resources including CSS
○ Parse CSS and construct CSSOM
○ Eval heavy JavaScript (especially in recent web app)
○ etc...
● Runtime
○ Interact to user operations
○ Fetch data and render async
○ etc...
Performance metrics are changing
1. Focused to Server Response (old SSR)
○ load event
○ DOMContentLoaded event
2. Focused to First View (CSR a.k.a SPA)
○ Speed Index
○ First Paint, First Contentful Paint, First Meaningful Paint
○ Async smooth page transition
3. Focusing to interactivity <= now
○ First CPU Idle (Time to interactive)
○ Responsibility on Runtime
https://dev.to/addyosmani/web-page-usability-matters-3aok
DOM manipulation is heavy
● Virtual DOM was born
○ to solve rendering performance
○ The Inner Working Of Virtual DOM
○ View library has implemented it such as React, Vue.js, Angular, Preact
● Virtual DOM achieve effective rendering, but...
○ Diff algorithm is also heavy
○ Can we use DOM in Worker?
● Split DOM manipulation
○ React Suspense provides async render with Promise
○ Vue.js mutation will use requestIdleCallback()
Off The Main Thread (inner browser)
● Parse and compile scripts in V8
● HTMLParser Redesign
● Will Worklets work on Worker thread?
Off The Main Thread (web page land)
● ampproject/worker-dom: DOM API implementation in Worker
○ using MutationRecord and postMessage
○ Browser-native Worker DOM is…?
● OffscreenCanvas: Canvas in Worker
○ Draw canvas on Worker Context
● Concurrent JavaScript idea by WebKit
https://threejs.org/examples/webgl_worker_offscreencanvas.html
More easier postMessage() !!!
postMessage() interface override
We could only pass string messages
to postMessage(), but new interface
is added.
postMessage(
// primitives, object, File, Blob, etc...
message,
// targetOrigin, transfer
options
);
postMessage(
// string
message,
// targetOrigin
targetOrigin,
// transfer
transfer
);
JavaScript "blöcks" proposal
We could only pass string messages
to postMessage(), but new interface
is added.
const result = await worker{|
const res = await fetch("people.json");
const json = await res.json();
return json[2].firstName;
|};
GoogleChromeLabs/comlink
> Comlink removes the mental
barrier of thinking about
postMessage and hides the fact
that you are working with workers.
// main.js
const MyClass = Comlink.proxy(new
Worker("worker.js"));
// `instance` is an instance of `MyClass` that
lives in the worker!
const instance = await new MyClass();
// logs “myValue = 42”
await instance.logSomething();
Further prospects
● More adoptive loading
○ By using Resource Hints, Intersection Observer, lazyload attribute, etc
● More effective prefetch
○ Like quicklink, Nikkei
● Will View libraries use Worker?
○ To calculate Virtual DOM diffs in Worker Thread
○ To apply Virtual DOM patch from Worker Thread
● Pray for browser optimizations 🙏

Introduction to Performance APIs

  • 1.
    Introduction to Performance APIs ChromeTech Talk Night #12 Shogo Sensui (@1000ch)
  • 2.
  • 3.
    Table of contents ●Lazy Loading ● Prefetch ● Off The Main Thread
  • 4.
  • 5.
    Intersection Observer > TheIntersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. const observer = new IntersectionObserver((entries) => { for (const entry of entries) { if (entry.isIntersecting) { console.log(entry); } } }); const el = document.querySelector('#el); observer.observe(el);
  • 6.
  • 7.
    Intersection Observer v2 IntersectionObserver v2 will detect the actual visiblity (like “opacity”). ● New options ○ trackVisiblity constructor option to track visiblity ○ isVisible property in IntersectionObserverEntry ● IntersectionObserver v2 demo const el = document.querySelector('#el); const observer = new IntersectionObserver((entries) => { for (const entry of entries) { if (entry.isVisible) { console.log(entry); } } }); observer.observe(el, { trackVisiblity: true });
  • 8.
    Browser native lazy-loading lazyloadattribute to load if display with-in viewport. ● will be enabled on... ○ <img> ○ <iframe> ● Lazyload images and iframes by bengreenstein · Pull Request #3752 · whatwg/html. ● Blink LazyLoad Design Docs (public) <img src="https://example.com/image.jpg" lazyload="on"> <iframe src="https://google.com" lazyload="on"> </iframe>
  • 9.
  • 10.
    Priority Hints forresource loading importance attribute to indicate resource priority. ● will be enabled on... ○ <img> ○ <iframe> ○ <script> ○ <link> ○ fetch() ● Priority Hints Draft Community Group Report 18 October 2018 <img src="https://example.com/image.jpg" importance="high"> <iframe src="https://example.com" importance="low"> </iframe> <script> fetch('https://google.com', { importance: 'high' }); </script>
  • 11.
    Resource Hints Resource Hintsprovides speculative loading which consists of... ● DNS Prefetch: host ● Preconnect: host ● Prefetch: resources ● Prerender: specified page <link rel="dns-prefetch" href="//example.com/"> <link rel="preconnect" href="//example.com/"> <link rel="prefetch" as="image" href="https://example.com/high-priority.jpg"> <link rel="prerender" href="https://example.com/">
  • 12.
  • 13.
    Preload Preload provides aggressiveloading ● For nested resources for initial loading ○ e.g) Images referred in CSS ○ e.g) JavaScript loaded on JavaScript ● Similar to Resource Hints <link rel="preload" href="https://example.com/high-priority.jpg"> <link rel="preload" href="https://example.com/high-priority.js">
  • 14.
  • 15.
    GoogleChromeLabs/quicklink > Faster subsequentpage-loads by prefetching in-viewport links during idle time Speculative prefetch links with-in viewport using following APIs. ● Intersection Observer ● Prefetch (Resource Hints) ● requestIdleCallback() ● Network Information API. quicklink({ ignores: [ //api/?/, uri => uri.includes('.zip'), (uri, el) => el.hasAttribute('noprefetch') ] });
  • 16.
    Nuxt v2.4 supportsprefetching links in viewport > Nuxt.js will automagically prefetch the code-splitted pages linked with <nuxt-link> when visible in the viewport by default. This hugely improves the end user performances, inspired by quicklink.
  • 17.
    AMP is thebest example for Prefetch/Prerender AMP prefetch/prerender some resources to achieve instant loading ● Prefetch resources ○ from Google AMP Cache hosted on Google ● Prerender documents ○ AMP’s prerender differs from <link rel=preload> ■ Why AMP HTML does not take full advantage of the preload scanner
  • 18.
    AMP’s URL isa long-standing problem..
  • 19.
    Web Packaging willsolve the AMP’s URL problem Web Packaging consists of... ● Signed HTTP Exchanges: Signs request/response including URL with private keys and creates .sxg file ● Bundled HTTP Exchanges: Bundles subresources in response ● Loading Signed Exchanges: Loads signed .sxg file and displays the original URL instead of distributed URL
  • 20.
    🚀 Off TheMain Thread
  • 21.
    More rich, More heavy. WebPage’s payload is increasing continuously
  • 22.
    Main Thread isbusy ● Loading (almost described by Critical Rendering Path) ○ Fetch HTML ○ Parse HTML and construct DOM ○ Fetch sub-resources including CSS ○ Parse CSS and construct CSSOM ○ Eval heavy JavaScript (especially in recent web app) ○ etc... ● Runtime ○ Interact to user operations ○ Fetch data and render async ○ etc...
  • 23.
    Performance metrics arechanging 1. Focused to Server Response (old SSR) ○ load event ○ DOMContentLoaded event 2. Focused to First View (CSR a.k.a SPA) ○ Speed Index ○ First Paint, First Contentful Paint, First Meaningful Paint ○ Async smooth page transition 3. Focusing to interactivity <= now ○ First CPU Idle (Time to interactive) ○ Responsibility on Runtime
  • 24.
  • 25.
    DOM manipulation isheavy ● Virtual DOM was born ○ to solve rendering performance ○ The Inner Working Of Virtual DOM ○ View library has implemented it such as React, Vue.js, Angular, Preact ● Virtual DOM achieve effective rendering, but... ○ Diff algorithm is also heavy ○ Can we use DOM in Worker? ● Split DOM manipulation ○ React Suspense provides async render with Promise ○ Vue.js mutation will use requestIdleCallback()
  • 26.
    Off The MainThread (inner browser) ● Parse and compile scripts in V8 ● HTMLParser Redesign ● Will Worklets work on Worker thread?
  • 27.
    Off The MainThread (web page land) ● ampproject/worker-dom: DOM API implementation in Worker ○ using MutationRecord and postMessage ○ Browser-native Worker DOM is…? ● OffscreenCanvas: Canvas in Worker ○ Draw canvas on Worker Context ● Concurrent JavaScript idea by WebKit
  • 28.
  • 29.
  • 30.
    postMessage() interface override Wecould only pass string messages to postMessage(), but new interface is added. postMessage( // primitives, object, File, Blob, etc... message, // targetOrigin, transfer options ); postMessage( // string message, // targetOrigin targetOrigin, // transfer transfer );
  • 31.
    JavaScript "blöcks" proposal Wecould only pass string messages to postMessage(), but new interface is added. const result = await worker{| const res = await fetch("people.json"); const json = await res.json(); return json[2].firstName; |};
  • 32.
    GoogleChromeLabs/comlink > Comlink removesthe mental barrier of thinking about postMessage and hides the fact that you are working with workers. // main.js const MyClass = Comlink.proxy(new Worker("worker.js")); // `instance` is an instance of `MyClass` that lives in the worker! const instance = await new MyClass(); // logs “myValue = 42” await instance.logSomething();
  • 33.
    Further prospects ● Moreadoptive loading ○ By using Resource Hints, Intersection Observer, lazyload attribute, etc ● More effective prefetch ○ Like quicklink, Nikkei ● Will View libraries use Worker? ○ To calculate Virtual DOM diffs in Worker Thread ○ To apply Virtual DOM patch from Worker Thread ● Pray for browser optimizations 🙏