Speed/cost of localStorage
How fast is looking up a value in localStorage with Javascript?
Does anyone have links to any performance tests that indicate whether or not it is worth caching the data in a JavaScript object? Or does the browser already cache values that are accessed from localStorage anyway?
I am particularly interested in Firefox and Chrome implementations of localStorage.
Just made a small benchmark. What i plan to do is to get some data from localStorage quite often and i wondered will it block. While localStorage.getItem is synced operation it may sound scary but is it?
- 1st test to call 1 million times localStorage to get item which does exist.
- 2nd test to call 1 million times localStorage to get item which does NOT exist.
Results:
"Item found: 0.0007991071428571318ms per call"
"Item not found: 0.0006365004639793477ms per call"
In short - just use it. It takes no time. 0.0007 of 1 millisecond.
https://jsbin.com/resuziqefa/edit?js,console
let results = [];
let sum = 0;
localStorage.setItem('foo', 'foo bar baz foo bar baz foo bar baz foo');
for (let i = 0; i < 1000000; i++) {
let a = performance.now();
localStorage.getItem('foo');
let result = performance.now() - a;
sum += result;
results.push(result);
}
console.log(`Item found: ${sum / results.length}ms per call`);
results = [];
sum = 0;
for (let i = 0; i < 1000000; i++) {
let a = performance.now();
localStorage.getItem('bar');
let result = performance.now() - a;
sum += result;
results.push(result);
}
console.log(`Item not found: ${sum / results.length}ms per call`);
For what it's worth, here is a jsperf test.
The benchmark usage of localStorage
is significantly slower than access of a regular object properties in both FF7 and IE9. Of course, this is just a micro-benchmark, and does not necessarily reflect real-world usage or performance...
Sample pulled from my FF 7 run to show what "significantly slower" means, in ops/second:
native local-storage notes small set 374,397 13,657 10 distinct items large set 2,256 68 100 distinct items read-bias 10,266 342 1 write, 10 reads, 10 distinct items
Also, there are restrictions on what can be put in localStorage. YMMV.
Apples to apples
There is not much value in comparing localStorage
to object storage, the two have different purposes in JavaScript. It is likely that you will only need to touch localStorage
a few times in your app and the rest of the work will be done in memory.
Local Storage vs Cookies
A better comparison against localStorage
would be that of its classic counterpart, document.cookie
. Both localStorage
and document.cookie
's main purpose is to persist a value across browser refreshes.
I've put together an example on codsandbox.io
-
localStorage
is two orders of magnitude faster thandocument.cookie
. -
Object
storage is an order of magnitude faster thanlocalStorage
(irrelevant but added for reference).
localStorage
is by far the fastest mechanism to persist values across a browser refresh.
Note that I've precompiled cookie regex getters in order to make cookies as fast as possible and used the browser performance API for accurate measurements. All tests do a set of a unique key followed by a get of the same key.
I appreciate the efforts of the previous answers but found the benchmarks lacking. Here's a better micro-benchmark, do note, it's still a micro-benchmark. Always prefer measuring real performance bottlenecks to doing premature performance optimization.
Benchmarks are for reading and writing a single value, a list of a hundred objects, and a list of ten-thousand objects from and to localStorage.
TL;DR:
single read: 0.0004ms, write: 0.0114ms
small list read: 0.0325ms, write: 0.0498ms
large list read: 3.1787ms, write: 3.3190ms
Ran on a 3,1 GHz Quad-Core Intel Core i7. Chrome 79.
read local storage - single x 2,439,715 ops/sec ±0.91% (62 runs sampled)
read local storage - small x 30,742 ops/sec ±0.78% (62 runs sampled)
read local storage - large x 315 ops/sec ±1.30% (60 runs sampled)
write local storage - single x 88,032 ops/sec ±4.25% (33 runs sampled)
write local storage - small x 20,079 ops/sec ±1.89% (59 runs sampled)
write local storage - large x 301 ops/sec ±1.09% (60 runs sampled)
Test: read local storage - single
mean: 0.0004098839352502669ms
margin of error: ±0.000003731514453196282ms
devation: ±0.00001499080315635531ms
Test: read local storage - small
mean: 0.03252840093744983ms
margin of error: ±0.0002551322114660716ms
devation: ±0.001024955633672395ms
Test: read local storage - large
mean: 3.1786666666666674ms
margin of error: ±0.041479799689699ms
devation: ±0.16392915653288143ms
Test: write local storage - single
mean: 0.011359496605398242ms
margin of error: ±0.00048286808926899016ms
devation: ±0.0014152377493978731ms
Test: write local storage - small
mean: 0.04980309857651518ms
margin of error: ±0.0009408982120607311ms
devation: ±0.0036873348473201325ms
Test: write local storage - large
mean: 3.31899154589372ms
margin of error: ±0.03605551145015122ms
devation: ±0.14249224018921072ms
Here's a snippet to run it yourself if you wish.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.min.js"></script>
<script>
const suite = new Benchmark.Suite();
const genNum = () => Math.floor(Math.random() * 1000000);
const genObj = () => ({
target: String(genNum()),
swap: String(genNum()),
price: genNum()
});
const printStats = test =>
console.log(
`Test: ${test.name}
mean: ${test.stats.mean * 1000}ms
margin of error: ±${test.stats.moe * 1000}ms
devation: ±${test.stats.deviation * 1000}ms`
);
const singleNum = String(genNum());
const smallList = _.range(100).map(genObj);
const largeList = _.range(10000).map(genObj);
const singleKey = "single-key";
const smallKey = "small-key";
const largeKey = "large-key";
localStorage.setItem(singleKey, singleNum);
localStorage.setItem(smallKey, JSON.stringify(smallList));
localStorage.setItem(largeKey, JSON.stringify(largeList));
suite
.add("read local storage - single", function() {
const readData = localStorage.getItem(singleKey);
})
.add("read local storage - small", function() {
const readData = JSON.parse(localStorage.getItem(smallKey));
})
.add("read local storage - large", function() {
const readData = JSON.parse(localStorage.getItem(largeKey));
})
.add("write local storage - single", function() {
localStorage.setItem("single_write_key", singleNum);
})
.add("write local storage - small", function() {
localStorage.setItem("small_write_key", JSON.stringify(smallList));
})
.add("write local storage - large", function() {
localStorage.setItem("large_write_key", JSON.stringify(largeList));
})
.on("cycle", function(event) {
console.log(String(event.target));
})
.on("complete", function() {
this.forEach(printStats);
})
.run({ async: true });
</script>