[翻译]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 性能的相关因素 前言: 大部分人都一致认为一个数据库应用系统(这里的数据库应用系统概指所有使用数据库的系统)的性能瓶颈最容易出现在数据的操作方面,而数据库应用系统的 ...
随机推荐
- 【Android官方Training教程】Getting Started部分学习笔记
Getting Started Welcome to Training for Android developers. Here you'll find sets of lessons within ...
- Java NIO 和 IO 的区别详解
Java NIO为jdk1.4提供了新的API,本文主要来比较一下Java中NIO和IO的区别,Java初学者可以了解一下. 下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分 ...
- M - 小希的迷宫
跟N题是一样的,不过会爆栈,有两种解决办法,第一种加 #pragma comment(linker, "/STACK:102400000,102400000") 这一行代码,不过只 ...
- 微信/易信公共平台开发(二):自定义菜单的PHP实现(提供源码)
微信把公众号分成订阅号和服务号两种,服务号可以自定义菜单, 菜单大大方便了用户操作. 比如:公众服务号 "中国南方航空" 的自定义菜单如下图: 点菜单就可以直接进入操作了,方便! ...
- DataTable与Linq相互转换
DataTable通过dt.AsEnumerable()方法转换可用Linq查询,反之,Linq也可以转化为DataTableDataTable newDt = query1.CopyToDataTa ...
- 八、频繁模式挖掘Frequent Pattern Mining
频繁模式挖掘(Frequent Pattern Mining): 频繁项集挖掘是通常是大规模数据分析的第一步,多年以来它都是数据挖掘领域的活跃研究主题.建议用户参考维基百科的association r ...
- MVC三层架构编程(Dao、service、servlet 之间的关系)
木哈哈~先开心一会儿,人生的第一篇博客aaa.我一定好好写.不过之前也没怎么看别人写过,还是有点小激动呢,加油.好好总结,会总结的宝宝才会有提高! 今天想总结一下mvc三层架构模型编程,宝宝学习不怎么 ...
- 高级进阶DB2(第2版)——内部结构、高级管理与问题诊断
<高级进阶DB2(第2版)——内部结构.高级管理与问题诊断> 基本信息 作者: 牛新庄 出版社:清华大学出版社 ISBN:9787302323839 上架时间:2013-7-3 出版 ...
- 让jquery easyui datagrid列支持绑定嵌套对象
嵌套对象是指返回的json数据,是对象的某个属性自带有属性.而我们恰恰又需要这个属性,默认情况下easyui的datagrid是不支持绑定嵌套对象的.比如:datagrid的field属性只能为fie ...
- nginx 配置轮询服务
通常我们应用nginx做代理时,用到它的轮训服务 #设置轮询名称 upstream zyy{ server 127.0.0.1:8080 #本机的apache服务 } server { listen ...