5

We have some data stored in localstorage and we are using window.setInterval() to regularly update it every minute. In this interval we are continuously reading and writing the data.

Is it possible that concurrency issues can occur because we're using setInterval(), as multiple tabs can modify the data in localstorage simultaneously?


Edit 1: Explaining the scenario in detail:

Each tab is writing some data to localstorage against a key (say xyz) and also setInterval(), present in the running javascript, continuously checks the xyz key data. If some data exists against the key, then the setInterval callback sends it to the back end. Each tab running the same script will read the xyz key and append some data to the existing value after performing some logic.

I doubt that a concurrency issue may occur, like one tab may be reading the xyz key and adding data to the local storage and another tab might be doing the same thing at the same time. Now both will try to send the data at the same time, hence I may receive the same data 2 times in the back end.

Jost
  • 199
  • 1
  • 3
  • 16
Deepak Kumar
  • 1,669
  • 3
  • 16
  • 36
  • 1
    Done thanks for the answer and advice. – Deepak Kumar Jun 28 '19 at 10:57
  • 1
    Since window.setInterval() is an asyn function which waits in event Queue so there should not be any concurrency issues. – Adnan Jun 28 '19 at 11:04
  • where come original data ? from ajax call ? – Mister Jojo Jun 28 '19 at 11:18
  • @MisterJojo - What does it matter? The question is about reading and writing `localStorage`. – T.J. Crowder Jun 28 '19 at 11:20
  • @DeepakKumar - Just to be clear, this is data that's meant to be shared across the tabs, right? We could probably help you solve whatever the underlying problem is more precisely if we had more context. – T.J. Crowder Jun 28 '19 at 11:21
  • @T.J.Crowder Edited the question. If the question is still not clear enough, I can share the sudo code as well – Deepak Kumar Jun 28 '19 at 12:13
  • check the [storage event](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) instead of polling with `setInterval` – Thomas Jun 28 '19 at 12:25
  • 1
    @DeepakKumar - Why is the storage handled by a `setInterval` callback instead of being done by the tab when it makes a change? Also, like Thomas I was going to point you at the [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event: If you have Tabs A, B, and C and they're all subscribed to `storage` on `localStorage` (and they're from the same origin), when Tab B (for example) writes to `localStorage`, tabs A and C receive the `storage` event. Seems like it would relate to what you're doing (but I still don't understand what you're doing). – T.J. Crowder Jun 28 '19 at 12:37
  • the problem will be that you add asynchronous calls on the setInterval which is itself asynchronous, which could cause conflicts, and that you will be able to see more problems in case of failure on the ajax calls – Mister Jojo Jun 28 '19 at 13:33
  • @T.J.Crowder I made the code changes based by removing the setInterval() and only active tab is sending the data. But there may be a chance that if one tab is reading the local storage -> doing some operation -> updating it and while the other tab is reading and clearing the LS memory. There may be case one may add the data in LS after another tab already cleared it. Then we'll have data in LS which is already sent to the server and duplicity can occur on the server end. How can we avoid this scenario? and how likely this can happen? – Deepak Kumar Jul 10 '19 at 05:59

3 Answers3

1

Is it possible that concurrency issues can occur because we're using SetInterval() as multiple tabs can modify the data in local storage simultaneously?

There are two aspects to this:

  1. Are getItem/setItem (and their accessor equivalents) atomic?
  2. Can different tabs/windows doing a series of getItem/setItem calls have those calls interleaved?

On #1, surprisingly, the storage specification seems not to address this head-on. In a "Note" it says:

Note

This specification does not require that the above methods wait until the data has been physically written to disk. Only consistency in what different scripts accessing the same underlying list of key/value pairs see is required.

...which suggests to me that getItem/setItem will be atomic — that is, the datum you're getting/setting won't get corrupted if two threads call getItem/setItem at literally the same time.

Re #2, I don't think there are any guarantees, no. If each tab/window has its own thread, then in theory two of those threads could simultaneously enter the block of code doing these updates. Sometimes, tabs/windows share a single thread, in which case you'd be safe, but...

I would avoid having lots of different entries in localStorage that need to be updated in a coordinated way. Instead, I'd use a single entry with a structure. I usually use JSON for that. So getting the data looks like this:

let data = JSON.parse(localStorage.getItem("the-data")) || {/*...default structure here...*/};

and saving it looks like this:

localStorage.setItem("the-data", JSON.stringify(data));

so you could do

let data = JSON.parse(localStorage.getItem("the-data")) || {/*...default structure here...*/};
// ...modify the various parts of `data`...
localStorage.setItem("the-data", JSON.stringify(data));

then you're left with a simple race between the threads (the last one to write wins), but the stored data will be consistent.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

Added after Edit: There is one more possibility, you can try to find out which page/tab of yours is active (of your page) and then activate the timer only at active tabs, then lowering chance of occuring concurrency. Here is https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API api for visibility checks.

Seti
  • 2,169
  • 16
  • 26
0

In my opinion, it really depends on what you consider be "concurrency issues".

For the case of writing, I don't believe that you will have any issue, the browser will manage well what and when should write to localstorage. Your data will not be corrupted in the process.

For the case of reading, I believe that you will have problems when you are reading from the Tab1 but the last write was from the Tab2.

Ricardo Rocha
  • 14,612
  • 20
  • 74
  • 130
  • Thanks for the answer, I edited the question for more details. Does the browser maintain 2 callback queues for 2 different tabs in this case? – Deepak Kumar Jun 28 '19 at 12:16
  • 1
    @DeepakKumar - There is **always** a separate callback queue per window/tab, as I said earlier. The question is whether there is a single thread servicing those queues across the tabs or each tab has its own thread, and in the latter case, what that means -- which I address in my answer. – T.J. Crowder Jun 28 '19 at 13:06
  • I can't agree more with @T.J.Crowder :D – Ricardo Rocha Jun 28 '19 at 13:29
  • @T.J.Crowder as per this blog a domain across mutiple tabs will have a single thread, which means a single queue? https://itnext.io/how-javascript-works-in-browser-and-node-ab7d0d09ac2f – Deepak Kumar Jul 01 '19 at 04:44
  • @DeepakKumar - As I've said at least three times in comments and an answer: **Every tab/window has its own queue.** As I've said at least twice: Tabs/windows can share a thread. That thread then has to go back and forth between servicing the queues for each of them. – T.J. Crowder Jul 01 '19 at 07:25