State of Offline Storage APIs

Joshua Bell / Storage TLM - Google, SFO

jsbell@google / @inexorabletash

BlinkOn 6 - 2016 - Munich bit.ly/blinkon6-storage

"What do I use for offline storage in PWAs?"

TL;DR

  • URL addressable resources → Cache API
  • Other data → Indexed DB
    • With a Promise wrapper library…
    • And probably a shim for Safari...

Available in Windows, Workers, Service Workers

Storage Types

Cookies

  • Synchronous
  • No Worker support
  • Size-limited, only strings
  • Not hooked up to Quota Manager

Current work:

  • Improved, SW-friendly API (bsittler@)
  • All about authentication!

Set-Cookie: key=value; max-age=3600

...

Cookie: sid=1234; type=muppet; key=value

document.cookie = 'key=value; max-age=3600';

alert(document.cookie);

// 'sid=1234; type=muppet; key=value'

DOM Storage

  • Synchronous
  • No Worker support
  • Size-limited, only strings
  • Not hooked up to Quota Manager

Pro tip: async IPC for updates - so effectively async after first read

Current work:

  • Mojoification (layered services) (michaeln@)
  • Other browsers not fans of "just add an async API"

localStorage.setItem('key', 'value');

alert(localStorage.getItem('key'));

WebSQL

  • Asynchronous (callback-based)
  • No Worker support (unshipped!)
  • Spec: JS binding to SQLite

Current status:

  • Rejected by Edge, Firefox
  • Deprecate/Unship ASAP
    • Indexed DB support on Safari unusable through 10

openDatabase('my','1','Title', 1e6, db => {

db.transaction(tx => {

tx.executeSql(

'INSERT INTO mytable (uid, str) ' +

'VALUES (?,?)',

[1, 'hello'],

success => alert('succeeded'),

error => alert('failed'));

},

aborted => alert('aborted'),

committed => alert('committed’)

);

});

Indexed DB (1/3)

  • Asynchronous (event-based)
  • Windows, Workers, Service Workers
  • Indexes, transactions, cursors
  • Popular libraries:
    • localForage
    • PouchDB
  • Safari 10: Finally usable \o/

open = indexedDB.openDatabase('db', 1);

open.onupgradeneeded = e => {

open.result.createObjectStore('s');

};

open.onsuccess = e => {

let db = open.result;

let tx = db.transaction('s');

let s = tx.objectStore('s');

let rq = s.put('value', 'key');

rq.onsuccess = e => alert('succeeded');

rq.onerror = e => alert(e.message);

tx.oncomplete = e => alert('committed');

tx.onabort = e => alert(e.message);

};

Indexed DB (2/3)

Developer complaints:

  • "Asynchronous programming is hard!"
  • Mandatory complexity - schema versioning, transactions
  • “Not SQL” - very low level, no query language

Indexed DB (3/3)

Current work:

Future work:

  • Simpler API: default store, transactionless, ...
  • Query improvements: more primitives, query language, free text search, ...

try {

let db = await

indexedDB.openDatabase('db');

let tx = db.transaction('s');

let s = tx.objectStore('s');

await s.put('value', 'key');

alert('put ok');

await tx;

alert('committed');

} catch (ex) {

alert(ex.message);

}

AppCache

  • Declarative (some script control)
  • Real deployments do horrible hacks

Current work:

  • Fixing bugs 😭
  • Chrome: Deprecating HTTP support (jww@)
  • Firefox: Intent to Deprecate

CACHE MANIFEST

CACHE:
/

scripts/main.js

res/logo.png
res/stylesheet.css

NETWORK:
*

Cache API (c/o SW)

  • Asynchronous (Promise-based)
  • Windows, Workers, Service Workers
  • key = Request, value = Response

Current work:

  • Ownership split (Service Workers, Network, Storage) 💩💩💩
  • Need to finish v1, address bugs

Future work:

  • Transaction API?

let cache = await caches.open('c');

let req = 'http://example.com/';

let res = await cache.get(req);

if (!res) {

res = await fetch(req);

cache.put(req, res);

}

File System

  • Asynchronous (callback-based)
  • Windows and Workers (w/ sync API)
  • Sandboxed - not native file access

Current status:

  • No interest from other vendors (newer Moz proposal abandoned?)
  • Heavily used by apps/extensions
  • PERSISTENT variant popular

webkitRequestFileSystem(TEMPORARY, 1e6,

fs => {

fs.root.getFile('my.txt', {create:true},

entry => {

entry.createWriter( ... );

},

err => alert(err.message));

},

err => alert(err.message));

File API

  • File Upload (<input type=file>, drag & drop)
  • Directory Upload - MSFT and Moz (?) shipping webkit-prefixed API

Current work:

  • Blob Transport (dmurph@)
  • File API Spec - w3c.github.io/FileAPI (mek@)
  • Entries API spec - wicg.github.io/entries-api (jsbell@)

Future work:

  • Writable Files

Fundamentals

Quota: Size

Previous:

  • Pool size: (free space – chrome's current usage) / 3
  • Origin quota: pool size / 5
  • … so PWA gets at most 6% of free space on device

Current work: (michaeln@)

  • Pool size as fixed % of total disk space: (drive size - OS size) ✕ P
  • Origin quota: pool size / N
  • P and N are Finchable: Can we make both 1.0 ?
  • API: navigator.storage.estimate()

Quota: Eviction

While used space > pool size, evict an origin:

  • Previous: Least Recently Used origin first
  • New: Least Site Engagement first - metrics say maybe!?!

Persistent Storage Permission ("Durable Storage") - (dgrogan@, dmurph@)

  • Must be explicitly requested - navigator.storage.persist()
  • Request is auto-granted (no UX) based on heuristics
  • If granted, site is opted out of eviction
  • Currently an Origin Trial

Improved Storage UX (dknox@, rolfe@, dmurph@)

Device Settings:

  • Manage storage intent
  • Common options interstitial

Chrome Settings:

  • "Important Sites" detent

Future Work

In progress/planned:

  • Clear Storage Header / API (mkwst@, msramek@)
  • SD Cards (dknox@)

Speculative:

  • Directory download
  • Storage management events
  • Global transaction API
  • Data type handlers
  • Improved picker UX (e.g. photo browser)

Overview & State of Storage APIs - Google স্লাইডগুলি