原文地址:Is localStorage performance a problem?

如果说2012年对于web开发世界来说有什么值得记住的事的话,关于localStorage性能的争论一定高居榜首。这场争论开始于Christian Heilmann写的一篇文章: There is no simple solution for localStorage(中文版:本地存储并不简单)。在这篇文章里,他得出了几个关于localStorage性能差的几个论断。除此之外,他还建议对现有api进行改变以及对于可选api(IndexedDB、webSQL)的优化。

但是这篇文章的读者并不多,只有很少的文章进行深入分析。John Allsopp写了一篇叫localStorage perhaps not so harmful的文章,在这篇文章里他分析了通过localStorage读写10KB的数据的时间。我也写了一篇文章来说明我的观点: localStorage无罪!(In defense of localStorage)。在这篇文章里我比较了相同条件下的localStorage和cookie(和磁盘访问读写的性能差不多)的读写性能。我和John Allsopp根据分析得出的结论都认为localStorage的性能问题并没有严重到抛弃使用它的地步。

在和Mozilla的Taras Glek(在他自己的博客上写了一篇相关主题的文章:PSA: DOM localStorage considered harmful)交流之后,我意识到自己和John Allsopp的测试方法和localStorage真正的运行方式相比是有缺陷的。

localStorage的关键问题在于它是通过同步操作的方式来进行文件I/o操作。写入localStorage的数据都会保存到磁盘上,除非主动删除数据,否则数据是永远不会过期的。用过nodeJs的人都知道,对于文件的I/O是非常昂贵和不一致的(不可信赖)。任何时间点任何的程序都可以访问文件。举例来说,你注意到过当一个杀毒软件运行的时候你的电脑是如何慢下来的吗?在理想状态下,你读取的文件不会有其他程序在同一时间访问该文件。在极端坏的情况下,如果你想读取一个文件,就必须等待文件上的锁被释放(其他程序操作文件时会锁定文件)。

这就引申出一个浏览器的问题:到底什么时候磁盘的数据才应该被读取?只有两种可能。第一种,数据可以在页面加载时就被读取,这样可以确保后面的读取快速操作。当然,这也意味着localStorage将会影响页面的加载时间,即使localStorage读取的数据并不会使用。在理想情况下,你并不会注意到这有多大不同。但在极端坏的情况下,这可能会导致页面加载时间的延长。

第二种方式是在localStorage第一次被使用(JS操作)的时候再从磁盘读取数据。这样可以阻止对于页面加载的中断,但也意味着在第一次通过localStorage访问数据的时候浏览器会中断对于页面的处理(js执行、页面渲染等)。磁盘文件的所有localStorage数据都会被写进内存以加快后面对于localStorage数据的读取速度。同样地,通过localStorage保存的数据会首先写入内存,以后再写入到磁盘文件里,以加快写的速度。firefox和chrome都使用了第二种方式(opera好像也是如此,我没有验证过)。这也导致了通过像jsPerf这样从不加载页面的工具来测量localStorage的性能是很难保证准确度的。

现在问题已经很清楚了:第一次通过localStorage.getItem()读取数据的时间是不可预测的。此外,这是一个阻塞型方法,因此浏览器会停止处理页面直到数据从磁盘中读出。后面我和John Allsopp的一起合作的测试(第一次慢读取,后面的快读取)表明localStorage也不是那么坏。最近,Chromium的工程师William Chan做了一些通过测量第一次读取时间来判断localStorage性能的分析

William的分析结果表明在Windows, Mac, 和Linux上75百分位数(就是说75%的测验都是很快的,只有25%有点慢)的测验读取速度都很快。事实上,在Windows和Linux上,只有99百分位数(99%的测试的首次读取时间小于1s,只有1%的测试超过1s)的测试的首次读取时间超过一秒(Mac上仍旧小于1s)。如下图表所示:

注:百分位数(percentile)的概念参考百度百科http://baike.baidu.com/view/1323573.htm

William Chan’s localStorage Read Performance Numbers

Taras Glek在Google+ comment上说他也分析出firefox也有类似的性能特征。Taras Glek和William的结论都证明了localStorage的性能并不像我们一开始想的那样低下。

尽管如此,我还是自己做了一些试验。通过在高级浏览器下使用performance.now(),在不支持时使用Date对象的方式来测量localStorage的首次读取时间和后面的读取时间。下面是我的一些发现(除非特别声明,测试环境都是Windows 7):

  • 在chrome下,第一次读取花费大约1ms,后面的读取花费0ms;
  • 在Firefox下,第一次读取花费大约0.5ms,后面的读取花费大约0.1ms;
  • 在IE9下,第一次读取和后续的读取都花费0ms。我不确定IE是如何加载这些数据的,当IE采取的方式应该和其他浏览器大不一样;
  • 在opera下,第一次读取花费大约1ms,后面的读取花费0ms;
  • 在IOS 6下的Safari下,第一次读取花费了整整24ms,后续的读取花费0ms。

在上面的结论中有个有趣的现象,safari好像会把所有的数据都保存在内存中,直到应用程序关闭才再次读取磁盘。只要safari保持运行,数据读取将继续只花费0ms。

基于以上结果,我没有看到在桌面电脑上不使用localStorage的任何理由。虽然99百分位数有些差的数据,但这仅仅是一些极端值。从平均数来看,localStorage的性能在所有浏览器下还是表现的很好的,即使是第一次读取的时候。

在移动设备下还需要更多更深入的研究。在移动设备上对磁盘进行操作比桌面设备更加昂贵,我们应该尽量减少对于磁盘的操作。不过,至少在IOS下这种花费通过只有在每个应用程序session中才读取一次的方式减轻了很多。由于大多数情况下用户并不会关闭safari,因此我们应该判断是否有必要花费初始化读取数据的时间。如果24ms比从服务器读取相同资源的时间要少,那么通过localStorage存储数据的性价比就会很高。

总的来说,我还是觉得对于localSorage性能差的论断有点草率。最新的数据表明localStorage的性能并不像早期有些文章写的那样让人不敢使用这项技术。磁盘I/O操作虽然一般情况下比较慢,但这是一个很好的例子表明越多的人关注和亲身测试对于一些有争论的观点对人们错误的引导有很大的抑制作用(事实胜于雄辩)。有很多网站都在使用这个api,但并没有哪家网站公开宣称localStorage存在性能问题。没有了性能上的问题,虽然在页面加载时使用localStorage需要思量再三,但我还是会尽可能的使用localStorage。

补充:在windows 8的IE10下,默认localStorage是不可访问的。如果我们直接使用localStorage的话,控制台会报Error:拒绝访问。解决方式如下:Get the Internet Explorer script error which says "Access denied error for LocalStorage"

[翻译]localStorage性能的好坏的更多相关文章

  1. 【官网翻译】性能篇(四)为电池寿命做优化——使用Battery Historian分析电源使用情况

    前言 本文翻译自“为电池寿命做优化”系列文档中的其中一篇,用于介绍如何使用Battery Historian分析电源使用情况. 中国版官网原文地址为:https://developer.android ...

  2. Qualcomm_Mobile_OpenCL.pdf 翻译-8-kernel性能优化

    这章将会说明一些kernel优化的小技巧. 8.1 kernel合并或者拆分 一个复杂的应用程序可能包含很多步骤.对于OpenCL的移植性和优化,可能会问需要开发有多少个kernel.这个问题很难回答 ...

  3. Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译

    本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  4. Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译

    本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...

  5. Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译

    本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...

  6. Unity性能优化(1)-官方教程The Profiler window翻译

    本文是Unity官方教程,性能优化系列的第一篇<The Profiler window>的简单翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻 ...

  7. 最有效地优化 Microsoft SQL Server 的性能

      为了最有效地优化 Microsoft SQL Server 的性能,您必须明确当情况不断变化时,性能将在哪些方面得到最大程度的改进,并集中分析这些方面.否则,在这些问题上您可能花费大量的时间和精力 ...

  8. AlwaysON同步性能监控的三板斧

    延迟是AlwaysOn最大的敌人之一 延迟是AlwaysON的最大敌人之一.对AlwaysON而言,其首要目标就尽量减少(无法避免)主副本.辅助副本的数据延迟,实现主副本.辅助副本的“数据同步”.只有 ...

  9. ch6 影响 MySQLServer 性能的相关因素

    第6章影响 MySQLServer 性能的相关因素 前言: 大部分人都一致认为一个数据库应用系统(这里的数据库应用系统概指所有使用数据库的系统)的性能瓶颈最容易出现在数据的操作方面,而数据库应用系统的 ...

随机推荐

  1. 详解C语言的main函数

    如图所示:#include<stdio.h>这是一个头文件,包含的是C程序运行的C语言的库函数,只有包含了相关的头文件,在程序中才能调用.stdio表示输入输出控制.printf():就是 ...

  2. RMQ——[USACO Jan07] 均衡队形题解

    题目:[USACO Jan07] 均衡队形 描述: 题目描述 农夫约翰的 N (1 ≤ N ≤ 50,000) 头奶牛,每天挤奶时总会按同样的顺序站好.一日,农夫约翰决定为奶牛们举行一个“终极飞盘”比 ...

  3. gem安装时出现 undefined method `size' for nil:NilClass (NoMethodError) 的解决办法

    终端输入gem env 得到gem的PATH路径,比如 - GEM PATHS: - /usr/local/ruby/lib/ruby/gems/2.1.0 - /home/vagrant/.gem/ ...

  4. 转:有关Java泛型的类型擦除(type erasing)

    转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...

  5. 区分width()、css('width')、innerWidth()

    #widthTest1 { width: 200px; height: 200px; background-color: #00CCFF; -webkit-box-sizing: border-box ...

  6. AFNetworking (3.1.0) 源码解析 <四>

    这次主要看一下文件夹Security中的类AFSecurityPolicy----安全策略类. AFSecurityPolicy主要的作用是验证HTTPS请求证书的有效性,在iOS9之后,默认不能发送 ...

  7. iOS 设备和外部配件的通讯

    首先,如果我们的应用程序想跟外设传输数据,先要透过iphone的操作系统,也就是iphoneOS,而最开始的认证过程也是在外设和iphoneOS之间发生的,苹果为这个过程提供了一颗认证芯片(这颗芯片的 ...

  8. SKScene类

    继承自 SKEffectNode:SKNode:UIResponder:NSObject 符合 NSCoding(SKNode)NSCopying(SKNode)NSObject(NSObject) ...

  9. Trie和Ternary Search Tree介绍

    Trie树 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie树与二叉搜索树不同,键不是直接保存在节 ...

  10. UVa 340 Master-Mind Hints (优化查找&复制数组)

    340 - Master-Mind Hints Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_on ...