警报阻止期间未更新LocalStorage

时间:2019-06-25 10:24:45

标签: javascript google-chrome local-storage google-chrome-devtools

今天,我在本地存储方面遇到了怪异的行为,我将其分解为一个简单的场景。如果在写入值时出现警告框,则Chrome浏览器似乎无法同步localStorage

已打开2个浏览器选项卡。

Tab A 请求文件 read.html

    var item = localStorage.getItem('test');
    console.log('item before alert', item);

    alert('Pause!'); // don't close it before calling write.html

    item = localStorage.getItem('test');
    console.log('item after alert', item);

警告框显示“暂停!”将不会关闭。

另一个标签 B 正在请求文件 write.html

    var item = (localStorage.getItem('test') || '') + 'a';
    console.log('new item:', item);
    localStorage.setItem('test', item);

您可以看到该值已在浏览器(Chrome)Devtools中的localStorage中更新,但仅在选项卡 B 中之一中已更新。

这仅在Chrome中发生。 IE11和Firefox运行正常。有人知道这是设计使然还是Chrome中存在错误?

问候 马库斯

编辑:使用代码https://github.com/wondee/localStorage-bug

创建了一个github项目。

更新:在Artyoms回答之后,我试图等待分发,这对上一次console.log(..)之后在 read.html 中添加以下代码确实有所帮助:更改可以正确反映:

setTimeout(() => console.log('item after 1s:', localStorage.getItem('test')), 1);

2 个答案:

答案 0 :(得分:1)

根据spec(请仔细阅读以涵盖可能的问题)。

  

在与本地存储区域相关联的存储对象x上​​调用setItem(),removeItem()和clear()方法时,如果这些方法没有引发异常或如上定义“不执行任何操作” ,然后对于每个相关的全局对象的localStorage属性的Storage对象与除x之外的相同存储区域相关联的Document对象,发送存储通知

据我所知,基本上,当用户打开具有相同来源的新标签时,会创建存储副本。因此,当在一个选项卡中修改存储时-存储事件(任务已排队)发送到所有其他选项卡(对于相同的来源)以使其同步。

  

当用户代理要发送文档的存储通知时,用户代理必须使用StorageEvent在文档对象的相关全局对象上触发一个任务,以激发名为存储的事件。

但是在您的特殊情况下,由于同步alert(),在脚本完成并且调用堆栈为空之前,事件循环无法接收此排队的存储事件。

但是,一旦第一个选项卡中的脚本完成,事件循环就会拾取该事件并在其存储副本上反映更改。

但是规范中有明确的警告,由于没有锁定机制,因此应避免以示例中的方式更新相同的共享状态。

  

警告! localStorage属性提供对共享状态的访问。该规范未定义在多进程用户代理中与其他浏览上下文的交互,因此鼓励作者假定没有锁定机制。例如,站点可以尝试使用新值作为会话的唯一标识符来读取键的值,增加其值然后将其写回;如果网站同时在两个不同的浏览器窗口中执行两次此操作,则最终可能在两个会话中使用相同的“唯一”标识符,从而可能造成灾难性的后果。

答案 1 :(得分:0)

您是否尝试过在设置新值之前清除localStorage?尝试

localStorage.removeItem('test');
localStorage.setItem('test',item);