为什么 MacOS/iOS 设备中的 localStorage 在可用性检查后有时为空?

问题描述 投票:0回答:3

我在使用本地存储的 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;
  }
};
javascript ios web browser local-storage
3个回答
2
投票
如果该项目不存在,

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!');
}

2
投票

从技术上讲:您正在缓存检查结果,并返回缓存的结果。

如果

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;
...

0
投票

由于它仅适用于 iOS(您确定所有 macOS 浏览器都适用吗?),这可能是智能跟踪预防:

https://webkit.org/tracking-prevention/

因此,在 7 天没有用户与网站交互后,ITP 会删除用 JavaScript 创建的所有 Cookie 以及所有其他脚本可写存储。

© www.soinside.com 2019 - 2024. All rights reserved.