检查localStorage是否可用

114

我知道关于检查localStorage的问题有很多,但是如果有人手动关闭了浏览器中的localStorage怎么办?这是我用来检查的代码:

localStorage.setItem('mod', 'mod');
if (localStorage.getItem('mod') != null){
  alert ('yes');
  localStorage.removeItem('mod');
} else {
  alert ('no');
}

这是一个简单的函数,它可以正常工作。但是,如果我进入我的Chrome设置并选择“不保存数据”选项(我不记得确切的名称),当我尝试运行此函数时,我什么也看不到,只有Uncaught Error: SecurityError: DOM Exception 18。那么,有没有办法检查用户是否完全关闭了此选项?

更新:这是我尝试的第二个函数,我仍然没有得到任何响应(警报)。

try {
  localStorage.setItem('name', 'Hello World!');
} catch (e) {
  if (e == QUOTA_EXCEEDED_ERR) {
   alert('Quota exceeded!');
  }
}

仍然没有提供任何查看它是否工作的方式... - user2025469
7
如果出现异常,你就知道它不起作用了。 - PeeHaa
2
可能是重复的问题:如何检测浏览器是否支持HTML5本地存储 - T J
2
可能是检查HTML 5本地存储的重复问题。 - BuZZ-dEE
12个回答

176

使用 modernizr 的方法:

function isLocalStorageAvailable(){
    var test = 'test';
    try {
        localStorage.setItem(test, test);
        localStorage.removeItem(test);
        return true;
    } catch(e) {
        return false;
    }
}

if(isLocalStorageAvailable()){
    // available
}else{
    // unavailable
}

这种方法并不像其他方法那样简洁,但这是因为它被设计成最大化兼容性。

原始来源:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js

工作示例:http://jsfiddle.net/6sm54/2/


2
嗨,乔,当我运行你的函数(LS打开或关闭)时,出现了这个错误:“未捕获的SyntaxError:非法返回语句”。 - user2025469
1
@user2025469 这段代码旨在作为一个函数使用。 - Kiruse
1
抱歉,我应该提到的。我已经更新了我的答案并添加了演示,这样您就可以看到它正常工作了。 - Joe
1
Joe,这正是我一直在寻找的。当我关闭LS时,它会提示不可用。这只是一个基本的JavaScript函数,还是我需要在脚本中包含modernizr JS? - user2025469
13
注意!这种 Modernizr 方法在 localStorage 配额达到上限时将返回 false。如果你有处理 localStorage 清理的函数,那么应该编辑 catch 语句以启动适当的清理操作,如果异常名称为“e.name ==== 'QUOTA_EXCEEDED_ERR'”(Chrome)或“'NS_ERROR_DOM_QUOTA_REACHED'”(Firefox/Safari),或者在 IE 中“localStorage.remainingSpace === 0”。 - KrisWebDev
显示剩余3条评论

32

在依赖于localStorage的任何操作之前,我会检查它是否已定义:

if (typeof localStorage !== 'undefined') {
    var x = localStorage.getItem('mod');
} else {
    // localStorage not defined
}

更新:

如果您需要验证该功能是否存在并且它也没有被关闭,那么您必须使用更安全的方法。为了绝对安全:

if (typeof localStorage !== 'undefined') {
    try {
        localStorage.setItem('feature_test', 'yes');
        if (localStorage.getItem('feature_test') === 'yes') {
            localStorage.removeItem('feature_test');
            // localStorage is enabled
        } else {
            // localStorage is disabled
        }
    } catch(e) {
        // localStorage is disabled
    }
} else {
    // localStorage is not available
}

1
在给定的情况下,这只是一个功能,可以防止其他浏览器出错...所以这并没有真正回答问题。如果关闭,localStorage仍然在window中定义。 - Kiruse
1
你仍然会得到一个 DOM 错误...我真的不敢相信没有办法检查它是否完全关闭... - user2025469
2
这不是Chrome和Opera的安全方法... Safari也很可能不是,因为localStorage完全无法访问,会抛出异常。 - Shikkediel
你不需要那么多的 else... 只需要一个 try catch 就可以了。我看到你正在测试结果是否实际上是 'yes',但我不知道有什么用例实际上需要这样做。 - Stijn de Witt
如果其他东西/人已经设置了一个值'feature_test',你会把它吹走吗? - Max Waterman

24

检测本地存储的功能很棘手。您需要实际进入其中。这是因为 Safari 在私密模式下选择提供一个功能性的 localStorage 对象,但其配额设置为零。这意味着尽管所有简单的特性检测都将通过,但对 localStorage.setItem 的任何调用都将抛出异常。

Mozilla 的开发者网络关于 Web 存储 API 的条目中有一个专门介绍本地存储功能检测的独立部分。以下是该页面推荐的方法:

function storageAvailable(type) {
    try {
        var storage = window[type],
            x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return false;
    }
}

这是如何使用它的方法:

if (storageAvailable('localStorage')) {
    // Yippee! We can use localStorage awesomeness
}
else {
    // Too bad, no localStorage for us
}
如果您使用NPM,可以使用以下命令获取storage-available
npm install -S storage-available

然后像这样使用该函数:

if (require('storage-available')('localStorage')) {
    // Yippee! We can use localStorage awesomeness
}

免责声明: MDN文档部分和NPM软件包都是由我编写的。


我不确定为什么你不先使用getItem()方法,以防其他值已经使用了该值(然后再设回来)-虽然不太可能发生。 - Max Waterman
是的,这将使它更加健壮。在这段代码中,我通过选择唯一名称来使碰撞高度不可能发生,但你是对的,这种情况可能会发生。您可以考虑为NPM包提交PR。 - Stijn de Witt
实际上,我们可能会完全重新考虑首先进行特性检测的方法。现在我将所有对localStorage的调用都包装在try..catch中,并完全省略了特性检测。因为存储随时可能变满。我现在将其视为文件I/O...就像磁盘随时可能变满一样。 - Stijn de Witt
在我看来,try catch是更好的方法。在某些(尽管不寻常的)环境中,没有本地存储并尝试访问它会导致异常。 - Max Waterman

11

MDN 更新了存储检测函数。在2018年,它更加可靠:

function storageAvailable() {
    try {
        var storage = window['localStorage'],
            x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            storage && storage.length !== 0;
    }
}
如果浏览器支持localStorage,则窗口对象上将有一个名为localStorage的属性。但是,由于各种原因,仅断言该属性存在可能会引发异常。即使存在,这也不保证localStorage实际可用,因为各种浏览器提供禁用localStorage的设置。因此,浏览器可能支持localStorage,但不会将其提供给页面上的脚本。其中一个例子是Safari,在私人浏览模式下,我们可以得到一个空的localStorage对象,配额为零,从而使其无法使用。然而,我们仍然可能遇到合法的QuotaExceededError,这只意味着我们已经使用完所有可用的存储空间,但存储实际上是可用的。我们的特征检测应考虑这些情况。
参见此处localStorage特征检测的简要历史

这并不是我在iOS 12.1的Safari中看到的确切行为。我能够设置和检索它们 - 它们只是在我关闭该选项卡后不会持久化。即使我在同一选项卡中访问另一个网站并返回,我的保存数据仍然存在。所以不确定这条评论有多旧。 - Simon_Weaver
1
显然,这是一个已经修复的错误 - https://dev59.com/02Uq5IYBdhLWcg3wXvSa。必须假设如果用户处于私人模式,当他们离开并回来时,他们希望失去“会话”。 - Simon_Weaver
这不是我在iOS 12.1的Safari中看到的确切行为。我能够设置和检索它们 - 只是在关闭选项卡后它们不会持久化。是的。值得庆幸的是,WebKit开发人员变得聪明起来并改变了错误的行为。在旧版本中,当处于私人模式时,任何尝试写入localStorage的操作都会抛出超过配额的错误。这是意外的,并给开发人员带来了很多问题。在后来的版本中,他们将其更改为与其他浏览器和cookie的行为相匹配:它可以工作,但只要浏览器保持打开状态。 - Stijn de Witt
在移动设备上使用Safari的私密模式时,尝试从本地存储中写入或读取数据时,我没有遇到任何错误。Safari将什么也不做,并且会默默地失败。 - SomewhereDave
1
“静默失败”实际上是在隐私/无痕模式下的预期行为。您的代码可以运行,但是当窗口关闭时,您存储的内容会被清除。这与cookie的行为完全相同。当用户选择隐私/无痕模式时,他们希望在关闭窗口时不留下任何痕迹。我不会担心它。这是用户做出的选择,除非浏览器存在漏洞,否则没有办法在私人模式下存储东西在用户设备上。这是一项功能。 - Stijn de Witt

5

使用此函数可以检查本地存储是否可用,您可以控制可能的异常情况。

function isLocalStorageAvailable() {

    try {
        var valueToStore = 'test';
        var mykey = 'key';
        localStorage.setItem(mykey, valueToStore);
        var recoveredValue = localStorage.getItem(mykey);
        localStorage.removeItem(mykey);

        return recoveredValue === valueToStore;
    } catch(e) {
        return false;
    }
}

0

你可以尝试这种方法,随时验证本地存储的内容。

const name = localStorage.getItem('name');
if(name){
    console.log('Exists');
}else
{
    console.log('Not found');
}

0
你可以创建一个检查函数,尝试从localStorage中获取一个不存在的项目。当localStorage被打开时,通常会返回null。但是当localStorage被关闭时,将抛出错误。您不必为检查设置任何项目。
const checkLocalStorage = () => {
    try {
      localStorage.getItem("x");
      return true;
    } catch {
      return false;
    }
}

0

最好同时检查localStoragecookies的可用性,因为如果启用了cookie,浏览器可能会检测到localStorage可用并将其归类为object,但无法使用它。您可以使用以下函数来检测localStoragecookies

const isLocalStorage = () => {
  try {
    if (typeof localStorage === 'object' && navigator.cookieEnabled) return true
    else return false
  } catch (e) {
    return false
  }
}

1
就像另一个答案所解释的那样,这是Safari浏览器的一个bug,当处于私密模式时将localStorage设置为空对象。浏览器不应该这样做。Cookies和localStorage是完全不同的机制。 - Phil
1
这不是Safari的bug。您可以在Chrome中检查,禁用cookies,然后再试一次。 - Ruslan Korkin

0

我在Chrome、Firefox和Edge中尝试了这个解决方案,它都能正常运行。

if (localStorage.getItem('itemName') === null )
{
    // your code here ...
}

如果localStorage上的本地变量不存在,它将返回false。

-1
修改Joe的答案并添加一个getter可以使其更易于使用。使用以下代码,您只需简单地说:if(ls)...
Object.defineProperty(this, "ls", {
  get: function () { 
    var test = 'test';
    try {
      localStorage.setItem(test, test);
      localStorage.removeItem(test);
      return true;
    } catch(e) {
      return false;
    }
  }
});

为什么要踩?它是有效的,而且输入 ls 比输入 lsTest() === true 更好。...? - Ronnie Royston
它不起作用。你正在将一个对象分配给ls... 因此,if (ls)将始终评估为true。只需通过将您的get方法更改为get: function(){return false}来检查它,您就会看到。此外,键入ls也不是更好的选择... 如果您以聪明的方式编写代码,这个测试在您的代码中不会太频繁(如果您以聪明的方式编写它),那么为什么要用一个非常短的变量污染(全局)范围呢? - Stijn de Witt
你说得对。我得修复一下...谢谢! - Ronnie Royston
@StijndeWitt 现在它可以工作了。感谢您的反馈... 关于污染全局范围,我理解您的观点,但我认为这是一种观点。有人可能会发现键入 if(ls){... 是值得的。 - Ronnie Royston
检查函数的返回结果和获取器(getter)的结果不再需要添加 === true。输入 lsTest()ls 更具描述性,而 isLocalStorageAvailable() 则更好。最好避免使用获取器,因为它们可能会令人意外,因为在输入 ls 等时没有指示它将执行代码。在此处没有理由使用获取器。如果您真的不想要括号,则可以计算可用性一次并将结果存储在全局变量中。这样更容易思考(没有隐藏执行)且总体上更短。 - 1j01

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接