The release of KV Storage is a big deal for the web platform. It’s part of the Standard Library Proposal which could see a more extensive standard library being introduced for JavaScript.
Before jumping in to what kv-storage
is, let’s first discuss how we can store data within the browser. If I wanted to store some local data right now, one of my main options would be the use of localStorage.
With that in mind, let’s create a simple Todo application with JavaScript that takes advantage of localStorage
. We’ll need two files - index.html
and main.js
:
main.js
const TODOS_KEY = 'todos'; const ul = document.getElementsByTagName('ul')[0]; const showExistingTodos = todos => { if (todos.length > 0) { todos.map(todo => { addLi(todo); }); } }; const addTodo = () => { const input = document.getElementById('todoInput').value; if (input.length > 0) { addLi(input); saveTodo(input); document.getElementById('todoInput').value = ''; } }; const addLi = text => { const li = document.createElement('li'); li.appendChild(document.createTextNode(text)); ul.appendChild(li); }; const saveTodo = todo => { let loadedTodos = loadTodos(); loadedTodos = [...loadedTodos, todo]; localStorage.setItem(TODOS_KEY, JSON.stringify(loadedTodos)); }; const loadTodos = () => { const todos = JSON.parse(localStorage.getItem(TODOS_KEY)); return todos != null ? todos : []; }; const clearTodos = () => { localStorage.removeItem(TODOS_KEY); const todos = Array.from(document.getElementsByTagName('li')); todos.map(todo => ul.removeChild(todo)); }; const todos = loadTodos(); showExistingTodos(todos);
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div> <input id="todoInput" type="text" /> <button onclick="addTodo()">Add Todo</button> <button onclick="clearTodos()">Clear todos</button> </div> <ul> </ul> <script src="main.js"></script> </body> </html>
🐊 Alligator.io recommends:
ES6 for Everyone → A video course to learn modern JavaScript
ⓘ About this affiliate link
While this could definitely be improved, we now have an application that we can use as an example. If we try and add some Todo items and then refresh the page, we’ll see that they appear instantly!
Hmm… I did some research and found out that localStorage
is synchronous. What does that mean for our application?
Essentially, this means that calls to localStorage
will block rendering inside of the DOM. This may may represent a problem if we had lots of elements in localStorage
and will significantly impact performance.
Let’s take a look at an experimental built-in module named KV storage (for key/value storage). This is built on IndexedDB, an asynchronous storage API.
Why not use IndexedDB natively then?
The use of KV storage gives us a more intuitive API that is similar to localStorage
. We also don’t need to turn to a third party IndexedDB library, we can now use this directly from within the browser!
KV Storage
For this example we’ll need to enable Experimental Features within Chrome. Inside of your Chrome browser, navigate to the following address:
Select "Enabled" on Experimental Web Platform features: chrome://flags/#enable-experimental-web-platform-features.
It’s also a good idea to use Chrome Canary for any and all experimental/new Web features. I’ll be using it for our example.
We’ll now need to perform the following updates:
Inside of index.html
, import main.js
as a module:
<script type="module" src="main.js"></script>
Next, we can update our saveTodo
function to use storage.set()
instead of localStorage.setItem()
const saveTodo = async todo => { let loadedTodos = await loadTodos(); loadedTodos = [...loadedTodos, todo]; await storage.set(TODOS_KEY, loadedTodos); };
Our loadTodos
function uses storage.get()
instead of localStorage.getItem()
:
const loadTodos = async () => { const todos = await storage.get(TODOS_KEY); return todos != null ? todos : []; };
Notice here how we're dealing with the asynchronicity with ease using async/await functions.
Finally, we can improve our clearTodos
function by using storage.delete()
instead of localStorage.removeItem()
:
const clearTodos = () => { storage.delete(TODOS_KEY); const todos = Array.from(document.getElementsByTagName('li')); todos.map(todo => ul.removeChild(todo)); };
We’ll also need to expose these to the window
object:
window.addTodo = addTodo; window.clearTodos = clearTodos;
Our application now works once again, but instead of localStorage
it uses the std:kv-storage
built-in Web module. The best thing about this? It uses IndexedDB under the hood!
This means everything is asynchronous (as referenced by our async
and await
promise calls, too).
Client support
What if the browser doesn’t support kv-storage
? At the moment, this is extremely likely. Luckily, there’s a polyfill available here: https://github.com/GoogleChromeLabs/kv-storage-polyfill.
I’d recommend you add this to your application if you plan on using kv-storage
in production at this stage.
Further reading
Google has prepared a demo on kv-storage
that you may find interesting to read. Here’s the URL: https://rollup-built-in-modules.glitch.me/