skip to Main Content

In which order storage event is received?

For example, tab_1 executes code

localStorage.set('key', 1);
localStorage.set('key', 2);

and tab_2 executes code

localStorage.set('key', 3);
localStorage.set('key', 4);

They execute code simultaneously.

Questions:

  • Can 2 be stored before 1?
  • Can 3 or 4 be stored between 1 and 2?
  • Can tab_3 receive storage events not in same order as values were stored in?(like if we stored 3, 4, 1, 2, can we receive 1, 2, 3, 4, or even in random order like 4, 1, 2, 3)

2

Answers


  1. Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Storage

    Can 2 be stored before 1?

    Javascript uses a single thread and executes the commands sequentially. So, if you have

    localStorage.setItem('key', 1);
    localStorage.setItem('key', 2);
    

    then my expectation would be that 1 is stored before 2 and 2 overrides 1, because setItem seems to be a simple function call and I don’t think it is involving async data. I am saying "I don’t think" because I do not know where its source-code is, but given the fact that it’s native code:

    enter image description here

    it’s up to the browser developers to implement it or integrate an implementation. I understand you want to factually find this out, so here’s a test:

    let one = 0;
    let two = 0;
    for (let i = 0; i < 10000; i++) {
        localStorage.setItem('key', 1);
        localStorage.setItem('key', 2);
        if (localStorage.getItem('key') == 1) one++;
        else two++;
    }
    console.log('one ' + one + ' two ' + two);
    

    Output in FireFox:

    one 0 two 10000

    and the same in Chrome. So the answer is no.

    Can 3 or 4 be stored between 1 and 2?

    If Javascript in two different tabs can run at the same time, then yes. Let’s write a test for that:

    setTimeout(function() {alert("the other tab")}, 5000);
    

    Run this code in a tab and quickly drift away to another tab. If in 5 seconds you see an alert while you are on the other tab, then the answer is yes. If not, then the answer is no. Running this in FireFox and drifting to another tab, I can see a red dot appearing on the now inactive tab, signifying that the alert happened there. The same happened at Chrome, but there the dot was orange. So the answer is yes.

    Can tab_3 receive storage events not in same order as values were stored in?(like if we stored 3, 4, 1, 2, can we receive 1, 2, 3, 4, or even in random order like 4, 1, 2, 3)

    This largely depends on the implementation, but I expect the loading of the data stored in localStorage to be behaving in the same manner upon each call. You can test it by running your codes in tab1 and tab2, respectively, possibly using setTimeout and opening further tabs, either before or after running your codes and check the value of localStorage in each. If they are the same, then the test’s result suggests that it is reliable indeed. If not, then the test disproved my hypothesis about reliability.

    Login or Signup to reply.
  2. JavaScript being single threaded (in the absence of Web Workers, who do not communicate through shared memory), the processing order within a browser tab is well defined.

    As for ordering across tabs, the spec cautions:

    The localStorage getter provides access to shared state. This specification does not define the interaction with other agent clusters in a multiprocess user agent, and authors are encouraged to assume that there is no locking mechanism. A site could, for instance, try to read the value of a key, increment its value, then write it back out, using the new value as a unique identifier for the session; if the site does this twice in two different browser windows at the same time, it might end up using the same "unique" identifier for both sessions, with potentially disastrous effects.

    Unfortunately, the precise meaning of "locking mechanism" is not defined here. The example illustrates that the value for a localStorage key may change at any time, even while a JavaScript thread is executing. That is, if a thread reads and then writes, another thread may have written in the meantime. It doesn’t explictly describe whether new values are guaranteed to show up in the same order to all windows.

    HTML Spec Issue 403 requests that the concurrency behavior of localStorage be specified better, but a solution has yet to be defined at this time …

    Implementation in Current Browsers

    Earlier versions of the WebStorage spec required localStorage implementations to use a Mutex, and current versions of Chrome and Firefox still do that, as the following test shows:

    In the first browser window:

    function test() {
        console.log("polling for changes");
        let x = localStorage.test;
        for (let i = 0; i < 100000000; i++) {
            let y = localStorage.test;
            if (x != y) {
                console.log("seeing new value", y);
                x = y;
            }
            if (i % 10000000 == 0) {
                let n = parseInt(x) + 1;
                console.log("setting new value", n);
                localStorage.test = n;
            }
        }
    }
    window.onstorage = e => console.log("seeing storage event", e);
    localStorage.test = 0;
    test();
    

    and while that is executing, in the second browser window:

    window.onstorage = e => console.log("seeing storage event", e);
    localStorage.test = parseInt(localStorage.test) + 20;
    

    Output in Chrome and Firefox:

    polling for changes
    setting new value 1
    seeing new value 1
    setting new value 2
    seeing new value 2
    setting new value 3
    seeing new value 3
    setting new value 4
    seeing new value 4
    setting new value 5
    seeing new value 5
    setting new value 6
    seeing new value 6
    setting new value 7
    seeing new value 7
    setting new value 8
    seeing new value 8
    setting new value 9
    seeing new value 9
    setting new value 10
    seeing new value 10
    undefined
    seeing storage event StorageEvent {isTrusted: true, key: 'test', oldValue: '10', newValue: '30', …}
    

    That is, in the current version of these browsers, the execution of code accessing localStorage is delayed until a mutex is obtained, causing the javascript threads execute in sequence (not in parallel, as the spec language encourages us to assume).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search