22
loading...
This website collects cookies to deliver better user experience
You're retaining an application's state, such as the active panel, chosen theme, input options, etc.
You're storing data locally, perhaps for practicality, performance, privacy, or pre-upload reasons.
You're creating a Progressive Web App which works offline and has no server-side requirements other than the initial download and updates.
The OS, browser, plugins, or user can block or delete data depending on the storage space available, supported technologies, vendor policies, configuration settings, etc.
Temporary data is often retained beyond the session. For example, you can close then reopen a browser tab and data should remain available.
Current options. APIs you can use today in all modern and most older browsers.
Future options. Experimental APIs which should be stable within a few years.
Past options. Deprecated APIs you should avoid at all costs!
window
object, e.g.// is localStorage available?
if (typeof localStorage !== 'undefined') {
// yes!
}
try/catch
block to detect failures:try {
localStorage.setItem('myObject', myObject);
}
catch (e) {
console.log('localStorage failed:', e);
}
.estimate()
method returns:quota
property: the space available to the domain, andusage
property: the space already in use.
(async () => {
// Storage API support
if (!navigator.storage) return;
const storage = await navigator.storage.estimate();
console.log(`permitted: ${ storage.quota / 1024 } Kb`);
console.log(`used : ${ storage.usage / 1024 } Kb`);
console.log(`% used : ${ Math.round((storage.usage / storage.quota) * 100) }%`);
console.log(`remaining: ${ Math.floor((storage.quota - storage.usage) / 1024) } Kb`);
})();
const
a = 1,
b = 'two',
c = {
one: 'Object',
two: 'three'
};
// locate a DOM node
const element = document.getElementById('mycomponent');
// store values
element.myValue1 = 1;
element.setAttribute('myValue2', 2);
element.dataset.myValue3 = 3;
// retreive values
console.log( element.myValue1 ); // 1
console.log( element.getAttribute('myValue2') ); // "2"
console.log( element.dataset.myValue3 ); // "3"
element.myValue1
) makes no change to the HTML itself and uses the prototypal nature of JavaScript objects..setAttribute()
and .getAttribute()
. Be careful not to use an HTML attribute with associated functionality such as disabled
or hidden
.
the dataset
property. This appends an attribute prefixed with data-
so it will not have default functionality.
the classList
API to add or remove classes from the class
attribute. These cannot (easily) have a value assigned so are most practical for retaining Boolean variables.
window.localStorage
for persistent data, andwindow.sessionStorage
for temporary session data.localStorage.setItem('value1', 1);
localStorage.getItem('value1'); // "1"
localStorage.removeItem('value1'); // gone
storage
event in all other browser tabs/windows on the same domain so your application views can update as necessary:window.addEventListener('storage', e => {
console.log(`key changed: ${ e.key }`);
console.log(`from : ${ e.oldValue }`);
console.log(`to : ${ e.newValue }`);
});
name
used by another componentasync/await
operations. You can Promisify it with wrapper functions, e.g. create a database connection when passed a name, version number, and upgrade function called when the version changes:// connect to IndexedDB database
function dbConnect(dbName, version, upgrade) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName, version);
request.onsuccess = e => {
resolve(e.target.result);
};
request.onerror = e => {
console.error(`connect error: ${ e.target.errorCode }`);
};
request.onupgradeneeded = upgrade;
});
}
mystore
object store:(async () => {
const db = await dbConnect('db', 1.0, e => {
db = e.target.result;
db.createObjectStore('mystore');
})
})();
db
connection to .add
new data items in a transaction:db.transaction(['mystore'], 'readwrite')
.objectStore('mystore')
.add('the value', 'key1')
.onsuccess = () => console.log( 'added' );
db.transaction(['mystore'], 'readonly')
.objectStore('mystore')
.get('key1')
.onsuccess = data => console.log( data.target.result );
// open a cache
const cache = await caches.open( 'myCache' );
// fetch and store response
await cache.add( '/myfile.json' );
const
// open cache
cache = await caches.open( 'myCache' ),
// fetch stored response
resp = await cache.match( '/myfile.json' ),
// get content as text
response = await resp.text();
document.cookie
API is simplistic with name/value pairs separated by an equals symbol (=
):document.cookie = 'cookie1=1';
document.cookie = 'cookie2=two';
encodeURIComponent()
may be necessary:document.cookie = `cookie3=${ encodeURIComponent('Hello world!') }`;
option | description |
---|---|
;domain= |
cookies are only accessible to the current domain, but ;path=site.com permits use on any subdomain |
;path= |
cookies only available to the current and child paths, ;path=/ permits use on any path |
;max-age= |
the cookie expiry time in seconds |
;expires= |
a cookie expiry date, e.g. ;expires=Mon, 12 July 2021 11:22:33 UTC (format with date.toUTCString() ) |
;secure |
send the cookie over HTTPS only |
;HTTPOnly |
cookies are server-only and not available to client-side JavaScript |
const state = { id:123 };
document.cookie = `state=${ encodeURIComponent(JSON.stringify(state)) }; path=/; max=age=600`;
document.cookie
string to extract name and value pairs using a function such as:const state = cookieValue('state');
// cache of parsed cookie values
let cookieCache;
// return a cookie value
function cookieValue(name) {
if (!cookieCache) {
cookieCache = cookieCache || {};
// parse
document.cookie
.split('; ')
.map(nv => {
nv = nv.split('=');
if (nv[0]) {
let v = decodeURIComponent( nv[1] || '' );
try { v = JSON.parse(v); }
catch(e){}
cookieCache[ nv[0] ] = v;
}
});
}
// return cookie value
return cookieCache[ name ];
}
max-age
and Expires
async function save( blob ) {
// create handle to a local file
const handle = await window.showSaveFilePicker();
// create writable stream
const stream = await handle.createWritable();
// write data
await stream.write(blob);
// close the file
await stream.close();
}
window.name
property sets and gets the name of the current window. This was typically used to keep track of several windows/tabs, but the browser retains the string value between refreshes or linking elsewhere.window.name
will accept a few megabytes of string data:let value = { a:1, b:2, c:3 };
window.name = JSON.stringify( value );
let newValue = JSON.parse( window.name );
window.name
was never designed for data storage but was often used as a hack or to polyfill localStorage
APIs in IE7 and below.window.name
when you link elsewhere.// create database (name, version, description, size in bytes)
const db = openDatabase('todo', '1.0', 'to-do list', 1024 * 1024);
db.transaction( t => {
// create table
t.executeSql('CREATE TABLE task (id unique, name)');
// add record
t.executeSql('INSERT INTO task (id,name) VALUES (1, "write article")');
});
// output all items
db.transaction( t => {
t.executeSql(
"SELECT * FROM task",
[],
(t, res) => { console.log(res.rows); }
);
});
CACHE MANIFEST
# cache files
index.html
css/style.css
js/main.js
images/image.png
# use from network when available
NETWORK:
network.html
# fallback when not available
FALLBACK:
. fallback.html
images/ images/offline.png