我在使用本地存储的 Web 应用程序中遇到了一个问题,虽然不是很常见,但仍然定期发生。
该问题仅发生在 iOS/macOS 设备中,无论浏览器如何,记录的错误如下:
TypeError:“null”不是对象(评估“localStorage.getItem”)
以下是代码的工作原理;有一个函数 (
isLocalStorageSupported
) 检查是否支持本地存储,还有另一个函数 (getLocalData
) 在尝试从存储中获取数据之前使用它。
在检查本地存储完成并返回 true 后抛出错误,但是当尝试从本地存储获取密钥时,下一行会莫名其妙地(?)抛出,因为该阶段的存储变量似乎为空。
我不清楚这是如何发生的,因此我的问题。
// The function that checks availability
const isLocalStorageSupported = (() => {
let localStorageSupported = null;
return () => {
if (localStorageSupported !== null) {
return localStorageSupported;
}
try {
localStorage.setItem('check', 'check');
localStorage.getItem('check');
localStorage.removeItem('check');
localStorageSupported = true;
} catch (error) {
localStorageSupported = false;
console.error('localStorage not supported');
}
return localStorageSupported;
};
})();
const getLocalData = (key) => {
if (isLocalStorageSupported()) { // This check is successful
let data = localStorage.getItem(key); // This line throws a TypeError!
if (!data) {
return;
}
return data;
}
};
localStorage将NOT抛出错误。它将返回 null:
//Purpose of this is to generate a completely random key to prove my point
let randomKey = String.fromCharCode(...crypto.getRandomValues(new Uint8Array(100))).match(/[A-Z]|[a-z]|[0-9]/g).join('');
//Get the value associated with the key (there is none)
console.log(localStorage.getItem(randomKey)); //--> null
如果您需要检查浏览器是否支持 localStorage,请按以下方式检查:
let localStorageSupported = 'localStorage' in window;
//this is equal to !!window.localStorage or Boolean(window.localStorage)
if (!localStorageSupported) {
alert('Get a new browser!');
}
从技术上讲:您正在缓存检查结果,并返回缓存的结果。
如果
localStorage
在第一次调用 isLocalStorageSupported()
时有效,并且之后变得无效,则无需重新加载页面,您的函数仍将返回 true
。
“无效”可能是内置 localStorage 对象的状态发生变化,或者更可能是与全局
localStorage
对象混淆的某些函数。
额外的一点,可能不相关,但值得注意:
您的代码片段显示了对名为
localStorage
的非限定变量的访问(例如:不是 window.localStorage
),该变量可以由 javascript 框架中的某些代码提供或处理。
最简单的建议是不要缓存结果。
为了避免破坏
"check"
中可能存在的 localStorage
键,您可以使用更独特的键名称(例如:"__my_company_check__"
)。
您可以确认您的问题是否来自此缓存行为(注意:此建议仍然在每个调用站点引入未缓存的检查,它将允许您确定您的问题是否来自缓存测试值):
function uncachedCheck() { ... }
function cachedCheck() { ... }
if (uncachedCheck() !== cachedCheck()) {
alert('state of localStorage has changed !')
// feed extra information to Splunk ...
}
我没有好的建议来修复您的检查的缓存版本:也许检查
localStorage
是否仍然是同一个对象? (不过我不知道不同浏览器如何支持localStorage
)
let localStorageSupported = null;
let checkedValue = undefined;
try {
if ((localStorage === checkedValue) && (localStorageSupported !== null)) {
return localStorageSupported;
}
checkedValue = localStorage;
...
由于它仅适用于 iOS(您确定所有 macOS 浏览器都适用吗?),这可能是智能跟踪预防:
https://webkit.org/tracking-prevention/
因此,在 7 天没有用户与网站交互后,ITP 会删除用 JavaScript 创建的所有 Cookie 以及所有其他脚本可写存储。