[翻译]localStorage性能的好坏
原文地址: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性能的好坏的更多相关文章
- 【官网翻译】性能篇(四)为电池寿命做优化——使用Battery Historian分析电源使用情况
前言 本文翻译自“为电池寿命做优化”系列文档中的其中一篇,用于介绍如何使用Battery Historian分析电源使用情况. 中国版官网原文地址为:https://developer.android ...
- Qualcomm_Mobile_OpenCL.pdf 翻译-8-kernel性能优化
这章将会说明一些kernel优化的小技巧. 8.1 kernel合并或者拆分 一个复杂的应用程序可能包含很多步骤.对于OpenCL的移植性和优化,可能会问需要开发有多少个kernel.这个问题很难回答 ...
- Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译
本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
- Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译
本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
- Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译
本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...
- Unity性能优化(1)-官方教程The Profiler window翻译
本文是Unity官方教程,性能优化系列的第一篇<The Profiler window>的简单翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻 ...
- 最有效地优化 Microsoft SQL Server 的性能
为了最有效地优化 Microsoft SQL Server 的性能,您必须明确当情况不断变化时,性能将在哪些方面得到最大程度的改进,并集中分析这些方面.否则,在这些问题上您可能花费大量的时间和精力 ...
- AlwaysON同步性能监控的三板斧
延迟是AlwaysOn最大的敌人之一 延迟是AlwaysON的最大敌人之一.对AlwaysON而言,其首要目标就尽量减少(无法避免)主副本.辅助副本的数据延迟,实现主副本.辅助副本的“数据同步”.只有 ...
- ch6 影响 MySQLServer 性能的相关因素
第6章影响 MySQLServer 性能的相关因素 前言: 大部分人都一致认为一个数据库应用系统(这里的数据库应用系统概指所有使用数据库的系统)的性能瓶颈最容易出现在数据的操作方面,而数据库应用系统的 ...
随机推荐
- hadoop 运行 datanode , mac 系统
问题描述 今天使用 hadoop 时,发现无法通过下面命令上传文件到 hadoop 文件系统,会报错. bin/hadoop fs -put input . 运行 jps 后,输出如下: Resour ...
- 火狐解决 OCSP 回应包含过期信息的问题_firefox吧_百度贴吧
火狐解决 OCSP 回应包含过期信息的问题_firefox吧_百度贴吧 火狐解决 OCSP 回应包含过期信息的问题
- E - Just a Hook - hdu 1698(区间覆盖)
某个英雄有这样一个金属长棍,这个金属棍有很多相同长度的短棍组成,大概最多有10w节,现在这个人有一种魔法,他可以把一段区间的金属棍改变成别的物质,例如金银或者铜, 现在他会有一些操作在这个金属棍上,他 ...
- php中的后期静态绑定("Late Static Binding")
在我们以往中,在类中使用self关键字的时候都是指向了被调用方法定义时的类,而非原始的调用类. 例如: class Animal{ static $IQ_lv_avg = 1; public stat ...
- css中居中的居中方法
1:给div设置一个宽度,然后添加margin:0 auto属性 div{ width:200px; margin:0 auto; } 2:居中一个浮动元素 确定容器的宽高 宽500 高 300 的层 ...
- Thrift初探:简单实现C#通讯服务程序
Thrift是一种可伸缩的跨语言服务框架,它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,工作效率和无缝地与C++,C#,Java,Python和PHP和Ruby结合.thrift允许你定义一个 ...
- Jenkins+maven+git+sonar 系统持续集成&代码单測管理
Jenkins+maven+git+sonar 系统持续集成&代码单測管理 Jenkins的安装 Jenkins是基于Java开发的一种持续集成工具,用于监控持续反复的工作.功能包含: 1.持 ...
- VB.NET版机房收费系统---七仙女之系统登录
VB.NET第一版机房收费系统,告一段落,验收的时候.问题也是大大的存在,没实用上设计模式,什么触发器.存储过程,都没实用上.看看其她小伙伴的,七层实现登录?那是什么东东,相比較我的三层而言,多了两倍 ...
- Windows下连接调试Asus Nexus 7 Tablet
Linux和mac下都能够直接连接,可是windows下必须下驱动.官网上的driver无论用.管用的是 https://drive.google.com/uc?id=0Bw8B2a85Qa1jSld ...
- [Angular 2] Passing Template Input Values to Reducers
Angular 2 allows you to pass values from inputs simply by referencing them in the template and passi ...