随着html5本地存储的到来,web应用也会更加充满活力。下面是个人对html5本地存储的一些理解。
客户端持久化数据的历史:
HTTP cookie: 这个是客户端使用的最为通用的方式,但问题也很明显。典型情景是用户本想执行一个事务,但可能会因为cookie而在不同窗口中执行多个事务。例如,一个用户在两个不同的窗口中登录同一个网站购买机票。网站使用cookie来记录用户购买的车票,当用户在不同窗口之间点击时,cookie可能会导致用户为同一个航班购买两张机票。另外,cookie最多只能存储4KB数据,每个HTTP请求都要将其送回服务器。
我们真正想要的是:
-
更大的存储空间
-
客户端持久化
-
不受页面刷新的影响
-
不需要提交到服务器
HTML5本地存储:
Web Storage是目前支持最广泛的HTML5本地存储规范,几乎所有浏览器都支持。
浏览器通过实现localStorage等接口来支持webStorage。它让 web 页面能够以键值对的形式,在客户端web浏览器中将数据存储在本地的方法。就像 cookie 一样,这种数据在你离开 web 站点、关闭标签页、退出浏览器等等的时候依然保存。不同于 cookie 的地方是,这个数据不会被发送到远程 web 服务器(除非你自己手动发送)。
其使用非常简单:
var foo = "hello,localStorage";
localStorage.setItem("hello",foo);
var message = localStorage.getItem("hello");
通过注册“storage”事件可以感知数据值的变化。
window.addEventListener('storage', function(e) {
console.log(e.key + "'s value is changed from '" +
e.oldValue + "' to '" + e.newValue + "' by " + e.url);
}, false);
//A page
localStorage['foo'] = 'bar';
//B page
localStorage['foo'] = 'newBar'
FileSystem API
当我们不满足于键-值形式的本地存储,而是想要自己管理本地存储;或者觉得数据库的支持不够好,想拥有一个本地文件系统一样时,可能要考虑FileSystem API了。目前,只有chrome浏览器支持该特性。使用FileSystem API,web应用可以创建、读写、遍历存在于沙箱(sandbox)中的用户本地文件系统的子集。
典型的好处如下:
1. 持久上传
- 当文件或者目录被选择上传时,数据被拷贝到本地沙箱中,并且一次上传一部分。
- 可以在浏览器崩溃或者网络故障后重新启动上传。
2. 视频游戏等拥有大量多媒体资源的应用
- 下载压缩包,本地解压成目录结构。
- 下载与操作系统无关
- 支持预取策略,从而使体验更加流畅。
- 服务器端更加节省存储。
3. 音频、图片离线编辑、缓存加速
- 目录结构更加适合于该类型文件的组织。
- 被其他应用如iTunes、Picasa离线编辑
4. 离线视频观看
- 为后续的观看下载超过1GB的大文件。
- 方便快速seek播放
- 部分播放,不用video标签全部加载
5. 离线web 邮件客户端
- 下载附件,本地存储。
- 缓存用户选择的附件以便快速上传。
- 上传时可以作为多部分的post,而不是一次一个XHR里面的文件。
FileSystem API 代码示例,需要chrome以--unlimited-quota-for-files标志运行,或者chrome web app 的manifest中开启unlimitedStorage权限
<!DOCTYPE html>
<html>
<head>
<style>
.example {
padding: 10px;
border: 1px solid #CCC;
}
#example-list-fs ul {
padding-left: 0;
}
#example-list-fs li {
list-style: none;
}
#example-list-fs img {
vertical-align: middle;
}
button {
padding: 5px 8px;
cursor: pointer;
text-shadow: 1px 1px white;
font-weight: 700;
font-size: 10pt;
}
body {
font: 14px Arial;
}
</style>
</head>
<body>
<div id="example-list-fs" class="example">
<button>Add some files</button> <button>List files</button> <button>Remove all files</button>
<ul id="example-list-fs-ul"></ul>
</div>
<script>
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
var fs = null;
function errorHandler(e) {
var msg = '';
switch (e.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
document.querySelector('#example-list-fs-ul').innerHTML = 'Error: ' + msg;
}
function initFS() {
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(filesystem) {
fs = filesystem;
}, errorHandler);
}
var buttons = document.querySelectorAll('#example-list-fs button');
var filelist = document.querySelector('#example-list-fs-ul');
if (buttons.length >= 3) {
buttons[0].addEventListener('click', function(e) {
if (!fs) {
return;
}
fs.root.getFile('log.txt', {create: true}, null, errorHandler);
fs.root.getFile('song.mp3', {create: true}, null, errorHandler);
fs.root.getDirectory('mypictures', {create: true}, null, errorHandler);
filelist.innerHTML = 'Files created.';
}, false);
buttons[1].addEventListener('click', function(e) {
if (!fs) {
return;
}
var dirReader = fs.root.createReader();
dirReader.readEntries(function(entries) {
if (!entries.length) {
filelist.innerHTML = 'Filesystem is empty.';
} else {
filelist.innerHTML = '';
}
var fragment = document.createDocumentFragment();
for (var i = 0, entry; entry = entries[i]; ++i) {
var img = entry.isDirectory ? '<img src="http://www.html5rocks.com/static/images/icon-folder.gif">' :
'<img src="http://www.html5rocks.com/static/images/icon-file.gif">';
var li = document.createElement('li');
li.innerHTML = [img, '<span>', entry.name, '</span>'].join('');
fragment.appendChild(li);
}
filelist.appendChild(fragment);
}, errorHandler);
}, false);
buttons[2].addEventListener('click', function(e) {
if (!fs) {
return;
}
var dirReader = fs.root.createReader();
dirReader.readEntries(function(entries) {
for (var i = 0, entry; entry = entries[i]; ++i) {
if (entry.isDirectory) {
entry.removeRecursively(function() {}, errorHandler);
} else {
entry.remove(function() {}, errorHandler);
}
}
filelist.innerHTML = 'Directory emptied.';
}, errorHandler);
}, false);
}
// Initiate filesystem on page load.
if (window.requestFileSystem) {
initFS();
}
</script>
</body>
</html>
综上,HTML5的本地存储特性,将会给未来的web应用带来更丰富的特性,从而大幅提升用户体验。
参考资料:
http://www.html5rocks.com/en/tutorials/file/filesystem/#toc-introduction
http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#introduction
http://dev.w3.org/html5/webstorage/#introduction
http://www.devbean.info/2011/06/dive-into-html5-localstorage/