gpt4 book ai didi

javascript - localStorage线程安全吗?

转载 作者:行者123 更新时间:2023-12-03 03:14:12 45 4
gpt4 key购买 nike

我很好奇是否有可能通过同时在两个浏览器选项卡中覆盖 localStorage 条目来损坏它。我应该为本地存储创建互斥锁吗?
我已经在考虑这样的伪类了:

LocalStorageMan.prototype.v = LocalStorageMan.prototype.value = function(name, val) {
//Set inner value
this.data[name] = val;
//Delay any changes if the local storage is being changed
if(localStorage[this.name+"__mutex"]==1) {
setTimeout(function() {this.v(name, val);}, 1);
return null; //Very good point @Lightness Races in Orbit
}
//Lock the mutext to prevent overwriting
localStorage[this.name+"__mutex"] = 1;
//Save serialized data
localStorage[this.name] = this.serializeData;
//Allow usage from another tabs
localStorage[this.name+"__mutex"] = 0;
}

上面的函数意味着本地存储管理器正在管理本地存储的一个特定键 - 例如 localStorage["test"]。我想将其用于 greasomonkey 用户脚本,其中避免冲突是首要任务。

最佳答案

是的,它是线程安全的。但是,您的代码不是原子的,这就是您的问题所在。我将介绍 localStorage 的线程安全性,但首先,如何解决您的问题。

两个选项卡都可以一起通过if检查并写入相互覆盖的项目。处理这个问题的正确方法是使用 StorageEvent s。

当本地存储中的 key 发生更改时,这些可以让您通知其他窗口,以内置消息传递安全的方式有效地为您解决问题。 Here is a nice read about them 。我们举个例子:

// tab 1
localStorage.setItem("Foo","Bar");

// tab 2
window.addEventListener("storage",function(e){
alert("StorageChanged!"); // this will run when the localStorage is changed
});
<小时/>

现在,我对线程安全的 promise :)

如我所愿 - 让我们从两个 Angular 观察这一点 - 从规范和使用实现。

规范

让我们根据规范来证明它是线程安全的。

如果我们检查 specification of Web Storage我们可以看到它specifically notes :

Because of the use of the storage mutex, multiple browsing contexts will be able to access the local storage areas simultaneously in such a manner that scripts cannot detect any concurrent script execution.

Thus, the length attribute of a Storage object, and the value of the various properties of that object, cannot change while a script is executing, other than in a way that is predictable by the script itself.

它甚至进一步阐述:

Whenever the properties of a localStorage attribute's Storage object are to be examined, returned, set, or deleted, whether as part of a direct property access, when checking for the presence of a property, during property enumeration, when determining the number of properties present, or as part of the execution of any of the methods or attributes defined on the Storage interface, the user agent must first obtain the storage mutex.

强调我的。它还指出,一些实现者不喜欢将此作为注释。

实践

让我们证明它在实现中是线程安全的。

随机选择一个浏览器,我选择了 WebKit(因为我之前不知道该代码位于何处)。如果我们检查 Storage 的 WebKit 实现我们可以看到它有互斥体的份额。

让我们从头开始吧。当您调用 setItem 或分配时,会发生这种情况:

void Storage::setItem(const String& key, const String& value, ExceptionCode& ec)
{
if (!m_storageArea->canAccessStorage(m_frame)) {
ec = SECURITY_ERR;
return;
}

if (isDisabledByPrivateBrowsing()) {
ec = QUOTA_EXCEEDED_ERR;
return;
}

bool quotaException = false;
m_storageArea->setItem(m_frame, key, value, quotaException);

if (quotaException)
ec = QUOTA_EXCEEDED_ERR;
}

接下来,这发生在 StorageArea 中:

void StorageAreaImpl::setItem(Frame* sourceFrame, const String& key, const String& value, bool& quotaException)
{
ASSERT(!m_isShutdown);
ASSERT(!value.isNull());
blockUntilImportComplete();

String oldValue;
RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
if (newMap)
m_storageMap = newMap.release();

if (quotaException)
return;

if (oldValue == value)
return;

if (m_storageAreaSync)
m_storageAreaSync->scheduleItemForSync(key, value);

dispatchStorageEvent(key, oldValue, value, sourceFrame);
}

请注意此处的blockUntilImportComplete。让我们看看:

void StorageAreaSync::blockUntilImportComplete()
{
ASSERT(isMainThread());

// Fast path. We set m_storageArea to 0 only after m_importComplete being true.
if (!m_storageArea)
return;

MutexLocker locker(m_importLock);
while (!m_importComplete)
m_importCondition.wait(m_importLock);
m_storageArea = 0;
}

他们还添加了一个很好的注释:

// FIXME: In the future, we should allow use of StorageAreas while it's importing (when safe to do so).
// Blocking everything until the import is complete is by far the simplest and safest thing to do, but
// there is certainly room for safe optimization: Key/length will never be able to make use of such an
// optimization (since the order of iteration can change as items are being added). Get can return any
// item currently in the map. Get/remove can work whether or not it's in the map, but we'll need a list
// of items the import should not overwrite. Clear can also work, but it'll need to kill the import
// job first.

解释这一点是有效的,但它可以更有效。

关于javascript - localStorage线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22001112/

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com