上篇我们介绍了cookie、Web Storage和Web数据库技术,接下来的这一篇将对文件存储和离线应用进行介绍。
文件存储
Blob
概念
英文全称为Binary Large Object,即二进制大对象。
API
// 构造函数
// blobParts参数是一个由ArrayBuffer、Blob等组成的数组,options表示一个可选对象,可指定传入的MIME类型type和行结束符写入方式endings
Blob(blobParts[,options])
//文件大小,单位为B
size
//文件MIME类型,如"image/jpeg"
type
// 指定开始位置和结束位置截取指定数据,返回新的Blob对象
slice(start[[,end],contentType])
// 返回一个Promise对象,resolve结果是包含所有内容的ArrayBuffer
arrayBuffer()
// 返回一个Promise对象,resolve结果是包含所有内容的utf-8字符串
text()
// 返回一个Promise对象,resolve结果是能读取所有内容的ReadableStream
stream()
File
File与Blob的关系
通过执行下面表达式,可得知Blob是File的基类,所以能对Blob操作的,同样适用于File。自然,File拥有Blob的所有属性和方法。
file instanceof Blob; //true
常见获取方式
1.从input类型为file,返回的FileList中获取
2.从放置被拖拽对象到指定位置,返回的DataTransfer获取
3.构造函数创建
属性
// 文件最近一次的修改时间时间戳
lastModified
// 文件最近一次的修改时间Date对象
lastModifiedDate
// 文件名,含后缀
name
// 文件相对于用户选中的目录的相对路径,非标准,不推荐使用
webkitRelativePath
URL
概念
用于解析、构造、规范和编码URL。便于读取或修改URL内容。
API
//为便于理解各属性对应的内容,以var url = new URL("http://user:mudong@mudong.xyz/main?data=123#abc");作为示例。
//构造函数
// url参数可以绝对url或相对url,为相对url时需指定base参数,作参照路径。
URL(url[,base])
//哈希值,如上为#abc
hash
//主机名,如上为mudong.xyz
host
//完整链接,如上为http://user:mudong@mudong.xyz/main?data=123#abc
href
//源,如上为http://mudong.xyz
origin
//密码,如上为mudong
password
//路径名,如上为/main
pathname
//端口号,如上为""
port
//协议名,如上为”http“
protocol
//参数字符串,如上为"?data=123"
search
//参数字符串对象,提供参数字符串的基本操作方法:
// append
// delete
// entries
// forEach
// get
// getAll
// has
// keys
// set
// sort
// toString
// values
//如上通过url.searchParams.get('data')为123
searchParams
//用户名,如上为name
username
// 返回整个url
toString()
// 返回整个url
toJson()
// 创建一个DOMString,包含一个唯一的blob链接。参数可以是File、Blob或MediaSource
// 示例:
// URL.createObjectURL(new Blob([new ArrayBuffer(16)]))
// "blob:chrome://new-tab-page/3ee0ed55-a791-4e07-80e9-186d9029fe64"
URL.createObjectURL(obj)
// 销毁之前使用URL.createObjectURL创建的URL实例。参数是blob链接字符串
// 示例:
// URL.revokeObjectURL("blob:chrome://new-tab-page/3ee0ed55-a791-4e07-80e9-186d9029fe64")
// undefined
URL.revokeObjectURL(url)blob://URL、data://URL、file://URL的区别
data://URL对内容进行编码。
blob://URL对浏览器存储在内存中或者磁盘上的Blob的一个简单引用。
file:URL指向本地系统文件的一个文件,仅暴露文件路径、浏览目录的许可等,除此之外任何内容都会带来安全问题。
特点
blob:URL与创建其的脚本拥有相同源,只在同源的文档中有效,而file:URL是非同源的,相较起来blob:URL更灵活些。
blob:URL不是永久有效,一旦用户关闭或者离开包含创建Blob URL脚本的文档,该BLob URL就失效了。
blob:URL只允许通过GET请求获取,并且一旦获取成功,浏览器必须返回一个HTTP 200 OK的状态码,同时返回一个使用Blob type属性的Content-Type头部信息。
FileReader
概念
使Web应用能异步读取存储于计算机本地的文件内容或二进制缓冲数据。
API
//读文件产生的错误异常
error
//读状态,值可能为0,1,2,分别表示数据未加载,数据正加载,完成读操作
readyState
//文件内容
result
//停止读操作
abort()
//开始读数据内容,并以ArrayBuffer返回
readAsArrayBuffer()
//开始读数据内容,并以二进制字符串返回
readAsBinaryString()
//开始读数据内容,并以dataURL返回
readAsDataURL()
//开始读数据内容,并以普通文本返回
readAsText()
//监听停止读事件
onabort
//监听读错误事件
onerror
//监听读成功完成事件
onload
//监听读开始事件
onloadstart
//监听读完成事件,不论成功与否
onloadend
//监听读进度事件
onprogress
其他文件API
FileSystem/FileSystemSync
表示一个文件系统。通过window.requestFileSystem()访问。有两个属性,一个表示文件系统名的name属性,另一个表示文件系统根目录的root属性
FileSystemEntry/FileSystemEntrySync
表示文件系统中的一个单实体,可能是文件,也可能是目录。在拖拽使用中,通过DataTransferItem.webkitGetAsEntry()访问。具体api如下,
//获取该实体附属的文件系统
filesystem
//获取从根路径到该实体的完整绝对路径
fullPath
//实体是否是目录
isDirectory
//实体是否是文件
isFile
//实体名称
name
// 复制实体到指定位置
copyTo()
// 获取关于文件的元数据
getMetadata()
// 获取父目录实体
getParent()
// 移动实体到指定位置,或重命名实体
moveTo()
// 删除指定文件或目录,注意删除的目录必须是空的
remove()
// 返回识别该实体的url,形如filesystem:URL
toURL()FileSystemFileEntry/FileSystemFileEntrySync
表示文件系统中的一个文件。api同FileSystemEntry,只有一个独有方法file,创建一个新的可读文件对象并返回
FileSystemDirectoryEntry/FileSystemDirectoryEntrySync
表示文件系统中的一个目录。api同FileSystemEntry,独有方法如下,
// 创建FileSystemDirectoryReader对象,用于读取目录的中实体
createReader()
//获取指定的目录
getDirectory()
//获取目录下的指定文件
getFile()FileSystemDirectoryReader/FileSystemDirectoryReaderSync
用于访问目录下所有实体。只有一个方法readEntries,返回该目录下的所有实体数组。
Base64
概念
一种编码格式,即1个字节中只用6位存储数据,也就是说,原本用3个字节存储的数据,转换为base64则需占用4个字节进行存储。
希望能在处理文本数据的媒介上存储和传输二进制数据而设计。
提供的相关方法
编码为base64:
btoa(str)
解码base64:
atob(base64Str)
unicode问题
由于DOMString是16位编码的字符串,所以如果有字符超出了8位ASCII编码的字符范围时,在大多浏览器中对Unicode字符串调用btoa将会造成一个Character Out Of Range的异常。
需对方法增强,使之支持UTF16。以下是摘自MDN的其中一种实现方式。
function btoaUTF16(str) {
var u16Arr = new Uint16Array(str.length);
Array.prototype.forEach.call(u16Arr, function(el, idx, arr) {
arr[idx] = str.charCodeAt(idx);
});
return btoa(String.fromCharCode.apply(null, new Uint8Array(u16Arr.buffer)));
}
function atobUTF16(base64) {
var binary = atob(base64);
var u8Arr = new Uint8Array(binary.length);
Array.prototype.forEach.call(u8Arr, function(el, idx, arr) {
arr[idx] = binary.charCodeAt(idx);
});
return String.fromCharCode.apply(null, new Uint16Array(u8Arr.buffer));
}
Blob、Base64、ArrayBuffer间的转换
原理
利用FileReader API实现从Blob到base64字符串、ArrayBuffer的转换。
利用Typed Array实现base64字符串、ArrayBuffer到Blob的转换。
代码实现
//Blob转base64
function blobToB64(blob, cb) {
var reader = new FileReader();
reader.addEventListener('load', function() {
cb && cb(reader.result);
});
reader.readAsDataURL(blob, {
type: blob.type
});
}
//Blob转ArrayBuffer
function blobToAb(blob, cb) {
var reader = new FileReader();
reader.addEventListener('load', function() {
cb && cb(reader.result);
});
reader.readAsArrayBuffer(blob);
}
//ArrayBuffer转base64
function abToB64(arraybuffer, cb) {
blobToB64(abToBlob(arraybuffer), cb);
}
//ArrayBuffer转Blob
function abToBlob(arraybuffer, filename) {
var u8arr = new Uint8Array(arraybuffer);
if (filename) {
return new File([u8arr], filename);
} else {
return new Blob([u8arr])
}
}
//base64转ArrayBuffer
function b64ToAb(base64, cb) {
blobToAb(b64ToBlob(base64), cb);
}
//base64格式转Blob
function b64ToBlob(base64, filename) {
var arr = base64.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var binaryStr = atob(arr[1]);
var i = binaryStr.length;
var u8arr = new Uint8Array(i);
while (i--) {
u8arr[i] = binaryStr.charCodeAt(i);
}
if (filename) {
return new File([u8arr], filename, {
type: mime
});
} else {
return new Blob([u8arr], {
type: mime
})
}
}
离线Web应用
理解离线
无网络下仍然可以访问
不随着用户清除浏览器缓存而被清除
旧数据会被最近一次访问的新数据覆盖
离线配置
配置应用程序缓存清单文件
清单文件后缀名是 appcache。服务端响应清单文件时,需设置响应头的内容类型为'text/cache-manifest',否则不能缓存应用程序了。清单文件格式要求第一行必须为 CACHE MANIFEST,接下来紧跟要缓存的资源列表,一行一个资源。注释以#开头。示例如下,
CACHE MANIFEST
# 应用要缓存的资源列表
CACHE:
index.html
index.css
index.js
images/logo.png
# NETWORK区域标识该URL资源总通过网络获取。URL支持*通配符,表示任何不在清单中的资源,浏览器都将通过网络加载
NETWORK:
list.html
# FALLBACK区域的清单项每行包括两个URL,第一个是URL前缀,第二个是需要加载存储在缓存中的资源。匹配该前缀的URL所指定的资源从网络载入失败,就会用从缓存中访问第二个URL指定的资源代替
FALLBACK:
/articles 404.html在需要缓存的 HTML 页面指定缓存清单文件,在单页应用中有且只有一个页面需 被缓存,而在多页应用中可能会有多个
span style="box-sizing: border-box;">html>
<html manifest="app.appcache">
...
html>
提问:如何“卸载”离线 Web 应用?1.服务端删除清单文件 2.删除缓存的 HTML 页面中对清单文件的配置
缓存更新
缓存更新机制
在线状态下,浏览器异步检查清单文件是否有更新,若有,则新的清单文件及清单中列举的所有资源文件都将被下载,重新保存到应用程序缓存中。
提问:资源文件变化了,清单文件没变化,而浏览器只会检查清单文件是否变化。要让资源文件能重新下载,该怎么解决?每次资源文件发生变化,可以修改清单文件的版本号,这样保证能检测到清单文件变化,重新下载清单中的所有资源文件。
提问:为什么更新了资源后,访问时却不是更新后的资源?浏览检查清单文件和下载资源是异步的,也就是说,应用可能在资源下载未完成前先从缓存加载资源了,所以通常都是第二次访问才能看到更新的资源。
缓存对象 applicationCache
事件:
onchecking
每载入设置 manifest 属性的 HTML 文件时触发
onnoupdate
应用程序清单文件无变动时触发
ondownloading
应用程序清单文件有变动,监听清单文件和要缓存的资源列表的下载过程
onprogress
监听应用程序的清单文件和要缓存的资源列表的下载进度
oncached
未曾缓存的应用程序下载清单文件和资源结束后触发
onupdateready
曾缓存的应用程序下载清单文件和资源结束后触发
onerror
处于离线状态,无法检查清单文件时触发
onobsolete
处于在线状态,应用程序有缓存,但清单文件不存在时触发,且将应用程序从缓存中删除
属性:
UNCACHED
应用程序无设置 manifest 属性,未缓存
IDLE
清单文件检查完毕,并缓存了最新的应用程序
CHECKING
浏览器正在检查清单文件
DOWNLOADING
浏览器正在下载并缓存清单中列举的所有文件
UPDATEREADY
已经下载和缓存了最新版的应用程序
OBSOLETE
清单文件不存在,缓存将被清除
方法:
update
显式调用更新缓存算法,检测是否有最新版本的应用程序。
swapCache
通知浏览器弃用旧缓存,所有请求都从新缓存中获取。当状态属性为 UPDATEREADY 或 OBSOLETE 时,调用该方法才有意义,其他状态属性下调用直接抛异常。
其他
浏览器在线状态的检测与监听
检测浏览器是否在线
navigator.online 属性
监听浏览器在线状态变化
window.onoffline 事件
window.ononline 事件
离线应用数据同步
离线状态下,通过 localStorage 保存应用相关数据,在线状态下,将本地数据同步到服务器。
参考
JavaScript权威指南(第6版)
ES6标准入门(第2版)
https://developer.mozilla.org/zh-CN/docs/Web/API/Blob
https://developer.mozilla.org/en-US/docs/Web/API/File
https://developer.mozilla.org/zh-CN/docs/Web/API/URL
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
https://developer.mozilla.org/en-US/docs/Web/API/File_and_Directory_Entries_API
https://developer.mozilla.org/zh-CN/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache
到了这里,关于存储与离线的学习算告一段落了。感谢阅读!!!
让文章获得更多曝光
预览