考虑一种情况,浏览器有两个或多个指向同一来源的选项卡。不同选项卡的不同事件循环可能会在访问本地存储时导致竞争条件,并且不同的选项卡可能会覆盖彼此在本地存储中的更改。
我正在编写一个面临这种竞争条件的Web应用程序,因此我想了解可以在这种情况下使用的不同同步原语。
答案 0 :(得分:3)
我在the relevant W3C spec结束时阅读了comment和来自Ian Hickson的this blog post on the topic,表明所谓发生的事情是浏览器 - 全局互斥锁控制对每个域localStorage
的访问。每次检查本地存储时,JavaScript执行的每个单独的“线程”(参见下面我相当自信的意思)都必须尝试获取存储互斥(如果它还没有它)。一旦它获得互斥锁,它就不会放弃直到它完全完成。
现在,什么是线程,以及线程完成意味着什么?唯一有意义的事情(唯一真正符合Hixie声称互斥体使事情“完全安全”的事情)是线程是某些浏览器上下文中的JavaScript代码事件。 (请注意,一个可能的事件是刚刚加载了<script>
块。)浏览器中JavaScript的性质通常是<script>
块中的代码,或任何类型的处理程序中的代码事件,直到它停止;也就是说,运行到<script>
主体的末尾,否则运行直到事件处理程序返回。
因此,考虑到这一点,存储互斥锁应该做的是强制所有共享域脚本在尝试声明互斥锁时阻止其中一个数字已经拥有它。它们将一直阻塞,直到拥有的线程完成 - 直到<script>
标记代码耗尽,或者直到事件处理程序返回。这种行为将从规范中获得这种保证:
因此,存储对象的length属性以及该对象的各种属性的值在脚本执行时不能更改,而不是以脚本本身可预测的方式。
然而,似乎基于WebKit的浏览器(Chrome和Safari,也可能是Android浏览器,现在也许是Opera?)不会对互斥体的实现感到烦恼,这会让你陷入困境中这个问题。如果你关心这样的竞争条件(一种非常合理的态度),那么你可以使用博客文章中提出的锁定机制(由曾经或曾经为Stackoverflow工作的人)或者实现版本计数系统检测脏写。 (编辑 - 现在我考虑一下,一个RDBMS风格的版本机制会有问题,因为仍然是检查版本的竞争条件!)