101

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.

Mike
  • 3,855
  • 5
  • 30
  • 39

4 Answers4

65

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`);
Lukas Liesis
  • 24,652
  • 10
  • 111
  • 109
  • 9
    You need a point of reference, how does it compare to variable access? – Kugel Mar 14 '18 at 06:37
  • 7
    @Kugel this was done not to compare but to check if localhost store is working fast enough to have no, or at least no, impact on overall performance. I wonder how the test should be written to have a real comparison on things you want to compare and this is out of the scope of this question for sure. When actions happen in 0.0007ms scope even this test is probably not accurate enough and doesn't cover things how CPU works and JS engine itself. My interest was to check if localhost is "fast" in general. – Lukas Liesis Mar 14 '18 at 12:52
  • Have you tested this with big objects instead of a simple string? – Sergiu Jun 17 '18 at 07:54
  • @Sergiu 1. Localstorage stores strings only, no objects. 2. Depending on browser there are limits how much data can be stored and those limits are nothing big, like 5Mb. I don't know what is "big" for you. – Lukas Liesis Jun 17 '18 at 12:11
  • Actually I was asking if there's any performance difference when the value contains a big string instead of just a few chars? – Sergiu Jun 19 '18 at 06:46
  • Just click on jsbin link and update `foo bar baz foo bar baz foo bar baz foo` to anything you want. Also run 1st test with default values to check timing on your machine. For me there is no difference if item is not found and if it is found, it took 4x more time, which is still incredibly quick. I used string of 2000 characters. – Lukas Liesis Jun 19 '18 at 08:18
  • I like this answer best. The other answer compares it to object storage which is not an apples to apples comparison. It should compare cookie access (as well as complexity). `localStorage` is a much simpler API to use and most people will be reading it once or setting it once. The rest of the operations occur in simple variables in memory. – cchamberlain Jul 02 '19 at 06:36
  • @cchamberlain there are so many assumptions in your comment :) all tech usage depends on stack, application, developers. cookies, local storage is both simple APIs and may be used quite heavily sometimes. It's good to know that if you need to depend on its speed, at least local storage is super quick – Lukas Liesis Jul 02 '19 at 06:51
  • What assumptions? Maybe that the developer is experienced enough to know the primary usage of localStorage vs. object (in memory) storage. There are not a ton of options in the browser for device storage (short of getting into service workers). I was agreeing with your answer. – cchamberlain Jul 02 '19 at 08:48
  • @Kugel is this an apt comparison of storing in a variable array vs storing in local/session storage? https://jsbin.com/vetomenere/edit?js,console – Parth Kapadia Nov 04 '22 at 10:32
  • @ParthKapadia at such timing there are many additional things that may change the results. Also your test include string concatenation for some reason in 1st test which made 1st part 22 times slower. But of course in variable is faster then through any API layer. – Lukas Liesis Nov 04 '22 at 11:52
  • @LukasLiesis That is a usecase of mine. I am storing a few things in an array, which is frequently updated. I was wondering if it would be better to store this data in session storage (in a string by concatenation) instead of using an array. Speed is definitely a drawback, but I believe storing in an array would occupy RAM (which will be a drawback incase the size of array becomes too large, which is unlikely - i am expecting a few thousand array entries at max), while the session storage would use ROM. Correct me if I am wrong. – Parth Kapadia Nov 04 '22 at 12:06
54

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.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
  • 6
    But regular objects aren't persisted. This is like comparing variable access with SQL storage. They have separate purposes and the former is always much faster than the latter. – cchamberlain Jul 02 '19 at 06:39
  • 3
    @cchamberlain It is still important to know, e.g. when considering whether to cache frequently used data within the page (and potentially needing to manage consistency across multiple tabs/windows) or to always fetch it from `localStorage`. I'm currently facing this decision for an OAuth refresh token and other persistent application state. Coincidentally, another Lukas already discussed this below your answer. – Lukas Oct 13 '20 at 16:07
25

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 codesandbox.io

  • localStorage is two orders of magnitude faster than document.cookie.
  • Object storage is an order of magnitude faster than localStorage (irrelevant but added for reference).

localStorage is by far the fastest mechanism to persist values across a browser refresh.

localstoragevcookies

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.

cchamberlain
  • 17,444
  • 7
  • 59
  • 72
  • 5
    This is not the point, and doesn't answer the question. Maybe I want to decide if I should keep a cache of my shared variable in regular storage (and periodically update it) or just leave it in localStorage and check it frequently? That's the point of the question, and this doesn't answer it. – DJClayworth Oct 28 '19 at 15:57
  • 2
    Define "regular storage". Sticking a value into a global variable doesn't have much in common with `localStorage` from a use cases perspective. Reading data from `localStorage` takes it from the disk into memory, so you're comparing one thing, `A`, to `A + B`. One is for temporary use in memory and the other is for persistence to disk. You don't buy RAM and hard drives in the same aisle. This question sheds a bad light on `localStorage` and it's not even comparing it to its classical counterpart, cookies. – cchamberlain Oct 28 '19 at 23:04
  • 1
    if you look way to store object and try to do that with local storage, i bet most of the time will be consumed to move object to string and back. e.g. most popular way would be JSON stringify which is a kinda slow operation. – Lukas Liesis Dec 23 '19 at 07:53
  • @LukasLiesis its true that JSON stringify is very commonly used to serialize to string to insert into local storage, but that shouldn't be included in a benchmark of local storage itself. What I don't like about many answers to this question is that they compare localStorage access to regular variable access and the two have very little in common. For purposes of answering the question, localStorage doesn't seem to cache reads, but to call it "very slow" is a misnomer. It's much faster than its persistent alternatives (cookies). – cchamberlain Mar 12 '20 at 20:27
  • I think it's a valid comparison, since we can have cases in which we would preferably use object storage for a fast initialization and then save later using localStorage in a case where you need some data quickly add. – Theo Oliveira Jul 25 '23 at 16:52
16

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/lodash@4.17.15/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>
alextes
  • 1,817
  • 2
  • 15
  • 22