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
:
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);
<!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>
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!
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).
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.
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/
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!