第二十章 JavaScript API
Atomics 与 SharedArrayBuffer
多个上下文访问 SharedArrayBuffer 时,如果同时对缓冲区执行操作,就可能出现资源争用问题。Atomics API 通过强制同一时刻只能对缓冲区执行一个操作,可以让多个上下文安全地读写一个 SharedArrayBuffer。
Atomics 不是构造函数,因此不能使用 new 操作符调用,也不能将其当作函数直接调用。Atomics 的所有属性和方法都是静态的(与 Math 对象一样)
跨上下文消息
跨文档消息有时候也简称为 XDM(cross-document messaging),是一种在不同执行上下文(如不同工作线程或不同源的页面)间传递信息的能力
XDM 的核心是 postMessage() 方法
postMessage() 方法接收3个参数:消息、表示目标接收源的字符串和可选的可传输对象的数组(只与工作线程相关)
接收到 XDM 的消息后,window 对象上会触发 message 事件,这个事件是异步触发的,因此从消息发出到接收到消息可能有延迟。传给 onmessage 事件处理程序的 event 对象包含以下3方面重要信息
- data 作为第一个参数传递给 postMessage() 的字符串数据
- origin 发送消息的文档源
- source 发送消息的文档中 window 对象的代理
Encoding API
Encoding API 主要用于实现字符串与定型数组之间的转换
文本编码
File API 与 Blob API
File API 与 Blob API 是为了让 Web 开发者能以安全的方式访问客户端机器上的文件,从而更好地与这些文件交互而设计的
File 类型
HTML5 在 DOM 上为文件输入元素添加了 files 集合。当用户在文件字段中选择一个或多个文件时,这个 files 集合中会包含一组 File 对象,表示被选中的文件。每个 File 对象都有一些只读属性
- name:本地系统中的文件名
- size:以字节计的文件大小
- type:包含文件 MIME 类型的字符串
- lastModifiedDate:表示文件最后修改时间的字符串
FileReader 类型
FileReader 类型表示一种异步文件读取机制。类似于 XMLHttpRequest,不同的是该方法是从文件系统读取文件,而不是从服务器读取数据
FileReader 类型提供了几个读取文件数据的方法:
- readAsText(file, encoding):从文件中读取纯文本内容并保存在 result 属性中。第二个参数表示编码,是可选参数
- readAsDataURL(file):读取文件并将内容的数据 URI 保存在 result 属性中
- readAsBinaryString(file):读取文件并将每个字符的二进制数据保存在 result 属性中
- readAsArrayBuffer(file):读取文件并将文件内容以 ArrayBuffer 形式保存在 result 属性
因为读取方法都是异步的,所以每个 FileReader 会发布几个事件,其中最有用的事件是 progress、error 和 load
- progress:每 50 毫秒触发一次,与 XHR 的 progress 事件有相同的信息:lengthComputable、loaded 和 total。也可以在 progress 事件中读取 FileReader 的 result 属性,即使其中尚未包含全部数据
- error:会在由于某种原因无法读取文件时触发。触发 error 事件时,FileReader 的 error 属性会包含错误信息,这个属性是一个对象,该对象只有一个属性:code。这个错误码的值可能是 1(未找到文件)、2(安全错误)、3(读取被中断)、4(文件不可读)或 5(编码错误)
- load:事件会在文件完成加载后触发。如果 error 事件被触发,则不会再触发 load 事件
如果想提前结束文件读取,则可以在过程中调用 abort() 方法,从而触发 abort 事件。在 load、error 和 abort 事件触发后,还会触发 loaded 事件。loaded 事件表示在上述 3 种情况下,所有读取操作都已经结束
FileReaderSync 类型
FileReaderSync 类型是 FileReader 的同步版本。这个类型拥有与 FileReader 相同的方法,只有在整个文件都加载到内存之后才会继续执行。FileReaderSync 只在工作线程中可用
Blob 与部分读取
blob 表示二进制大对象( binary larget object ),是 JavaScript 对不可修改二进制数据的封装类型。包含字符串的数组、ArrayBuffers、ArrayBufferViews,甚至其他 Blob 都可以用来创建 blob。
blob 构造函数可以接收一个 options 参数,并在其中指定 MIME 类型
1 | console.log(new Blob(['foo'])) |
Blob 对象有一个 size 属性和一个 type 属性,还有一个 slice() 方法用于切分数据。另外也可以使用 FileReader 从 Blob 中读取数据
1 | …… |
只读取部分文件可以节省时间,特别是在只需要数据特定部分比如文件头的时候
对象 URL 与 Blob
对象 URL 有时候也称作 Blob URL,是指引用存储在 File 中数据的 URL。对象 URL 的优点是不用把文件内容读取到 JavaScript 也可以使用文件,只要在适当位置提供对象 URL 即可
要创建对象 URL,可以使用 window.URL.createObjectURL() 方法并传入 File 或 Blob 对象。返回值是一个指向内存中地址的字符串,这个字符串是 URL,可以直接在 DOM 中使用
以上示例展示了使用对象 URL 在页面中显示一张图片。与 FileReader 相比,对象 URL 不需要先读数据到 JavaScript 中,img 标签可以直接从相应的内存位置把数据读取到页面上,
只要对象 URL 在使用中,就不能释放内存。如果想表明不再使用某个对象 URL,可以把它传给 window.URL.revokeObjectURL()。页面卸载时,所有对象 URL 占用的内存都会被释放。不过,最好在不使用时就立即释放内存,以尽可能减少页面资源占用
读取拖放文件
必须监听 dragenter、dragover 事件的原因点击这里查看
媒体元素
属性
<video>
和 <audio>
元素提供了稳健的 JavaScript 接口。这两个元素有很多共有属性,可以用于确定媒体的当前状态,如下表所示:
属性 | 数据类型 | 说明 |
---|---|---|
autoplay | Boolean | 取得或设置 autoplay 标签 |
buffered | TimeRanges | 对象,表示已下载缓冲的时间范围 |
bufferedBytes | ByteRange | 对象,表示已下载缓冲的字节范围 |
bufferingRate | Integer | 平均每秒下载的位数 |
bufferingThrottled | Boolean | 表示缓冲是否被浏览器节流 |
controls | Boolean | 取得或设置 controls 属性,用于显示或隐藏浏览器内置控件 |
currentLoop | Integer | 媒体已经播放的循环次数 |
currentSrc | String | 当前播放媒体的 URL |
currentTime | Float | 已经播放的秒数 |
defaultPlaybackRate | Float | 取得或设置默认回放速率。默认为 1.0 秒 |
duration | Float | 媒体的总秒数 |
ended | Boolean | 表示媒体是否播放完成 |
loop | Boolean | 取得或设置媒体是否应该在播放完再循环开始 |
muted | Boolean | 取得或设置媒体是否静音 |
networkState | Integer | 表示媒体当前网络连接状态。0 表示空,1 表示加载中,2 表示加载元数据,3 表示加载了第一帧,4 表示加载完成 |
paused | Boolean | 表示播放器是否暂停 |
playbackRate | Float | 取得或设置当前播放速率。用户可能会让媒体播放快一些或慢一些。与 defaultPlaybackRate 不同,该属性会保持不变,除非开发者修改 |
played | TimeRanges | 到目前为止已经播放的时间范围 |
readyState | Integer | 表示媒体是否已经准备就绪。0 表示媒体不可用,1 表示已初始化,2 表示媒体可以开始播放(当前位置已经加载),但没有数据能播放下一帧的内容,3 表示当前及至少下一帧的数据是可用的(也就是说至少有两帧的数据),4 表示有足够的数据可以开始播放,如果网速得到保障,那么可以一直播放到底 |
seekable | TimeRanges | 可以跳转的时间范围 |
seeking | Boolean | 表示播放器是否正移动到媒体文件的新位置 |
src | String | 媒体文件源。可以在任何时候重写 |
start | Float | 取得或设置媒体文件中的位置。以秒为单位,从该处开始播放 |
totalBytes | Integer | 资源需要的字节总数(如果知道的话) |
videoHeight | Integer | 返回视频(不一定是元素)的高度。只适用于<video> |
videoWidth | Integer | 返回视频(不一定是元素)的宽度。只适用于<video> |
volume | Float | 取得或设置当前音量,值为 0.0 到 1.0 |
事件
事件 | 何时触发 |
---|---|
abort | 下载被中断 |
canplay | 回放可以开始,readyState 为 2 |
canplaythrough | 回放可以继续,不应该中断,readyState 为 3 |
canshowcurrentframe | 已经下载当前帧,readyState 为 1 |
dataunavailable | 不能回放,因为没有数据,readyState 为 0 |
durationchange | duration 属性的值发生变化 |
emptied | 网络连接关闭了 |
empty | 发生了错误,阻止媒体下载 |
ended | 媒体已经播放完一遍,且停止了 |
error | 下载期间发生了网络错误 |
load | 所有媒体已经下载完毕。这个事件已被废弃,使用 canplaythrough 代替 |
loadedmetadata | 媒体的元数据已经下载 |
loadeddata | 媒体的第一帧已经下载 |
loadstart | 下载已经开始 |
pause | 回放已经暂停 |
play | 媒体已经收到开始播放的请求 |
playing | 媒体已经实际开始播放了 |
progress | 下载中 |
ratechange | 媒体播放速率发生变化 |
seeked | 跳转已结束 |
seeking | 回放已移动到新位置 |
stalled | 浏览器尝试下载,但尚未收到数据 |
timeupdate | currentTime 被非常规或意外地更改了 |
volumechange | volume 或 muted 属性值发生了变化 |
waiting | 回放暂停,以下载更多数据 |
检测编解码器
canPlayType()
:该方法接收一个格式/编解码器字符串,返回一个字符串值:probably、maybe 或 “”(空字符串),其中空字符串是假值
1 | if(audio.canPlayType("audio/mpeg")){ |
在只给 canPlayType() 提供一个 MIME 类型的情况下,最可能返回的是 maybe 和空字符串。这是因为文件实际上只是一个包装音频和视频数据的容器,而真正决定文件是否可以播放的是编码。在同时提供 MIME 类型和编解码器的情况下,返回值的可能性会提高到 probably
1 | let audio = document.querySelector('.audio-player'); |
注意:编解码器必须放到引号中。同样,也可以在视频元素上使用 canPlayType() 检测视频格式
音频类型
<audio>
元素还有一个名为 Audio 的原生 JavaScript 构造函数,支持在任何时候播放音频。Audio 类型与 Image 类似,都是 DOM 元素的对等体,只是不需要插入文档即可工作。要通过 Audio 播放音频,只需创建一个新实例并传入音频源文件
创建 Audio 的新实例就会开始下载指定的文件。下载完毕后,可以调用 play() 来播放音频
原生拖放
拖放事件
在某个元素被拖动时,会(按顺序)触发以下事件:
1、dragstart
2、drag
3、dragend
在按住鼠标键不放并开始移动鼠标的那一刻,被拖动元素上会触发 dragstart 事件;拖动开始时,会触发 drag 事件,这个事件类型于 mouseover,即随着鼠标移动和不断触发;当拖动停止时(把元素放到有效或无效的放置目标上),会触发 dragend 事件
在把一个元素拖动到一个有效的放置目标上时,会依次触发以下事件:
1、dragenter
2、dragover
3、dragleave 或 drop
自定义放置目标
在把某个元素拖动到无效放置目标上时,会看到一个特殊光标(圆环中间一条斜杠)表示不能放下。即使所有元素都支持放置目标事件,这些元素默认也是不允许放置的。如果把元素拖动到不允许放置的目标上,无论用户动作是什么都不会触发 drop 事件
可以通过覆盖 dragenter 和 dragover 事件的默认行为,把任何元素转换为有效的放置目标,此时,drop 事件也会触发
在 FireFox 中,放置事件的默认行为是把 URL 放在放置目标上。这意味着把图片拖动到放置目标上会导致页面导航到图片文件,把文件拖动到放置目标会导致无效的 URL 错误。为阻止这个行为,在 FireFox 中必须取消 drop 事件的默认行为
dataTransfer 对象
dataTransfer 是 event 的属性,在拖放事件的事件处理程序外部无法访问
dataTransfer 对象有两个主要方法:getData() 和 setData()。
getData() 用于获取 setData() 存储的值。setData() 的第一个参数和 getData() 的唯一参数是一个字符串,表示要设置的数据类型
初始只支持设置由 IE 引入的 text 和 URL 两种数据类型,而后 HTML5 将其扩展为允许任何 MIME 类型。为向后兼容,HTML5 会把 text 映射到 text/plain,URL 映射到 text/uri-list
dataTransfer 对象实际上可以包含每种 MIME 类型的一个值,也就是说可以同时保存文本和 URL,两者不会覆盖。存储在 dataTransfer 对象中的数据只能在放置事件中读取。如果没有在 ondrop 事件处理程序中取得这些数据,dataTransfer 对象就会被销毁,数据也会丢失
从 文本框拖动文本时,浏览器会调用 setData() 并将拖动的文本以 text 格式存储起来。类似地,在拖动链接或图片时,浏览器会调用 setData() 并把 URL 存储起来。当数据被放置在目标上时,可以使用 getData() 获取这些数据。当然,可以在 dragstart
事件中手动调用 setData() 存储自定义数据
dropEffect 与 effectAllowed
这两个是控制在拖放操作中光标的效果,即给用户的视觉反馈。具体执行什么样的操作需要开发自己实现
dataTransfer 对象不仅可以用于实现简单的数据传输,还可以用于确定能够对被拖动元素和放置目标执行什么操作。为此,可以使用两个属性:dropEffect 和 effectAllowed
dropEffect 属性可以告诉浏览器允许哪种放置行为。这个属性有以下4种可能的值:
- none:被拖动元素不能放到这里,这是除文本框之外所有元素的默认值
- move:被拖动元素应该移动到放置目标
- copy:被拖动元素应该复制到放置目标
- link:表示放置目标会导航到被拖动元素(仅在它是 URL 的情况下)
在把元素拖动到放置目标上时,上述每种值都会导致显示一种不同的光标。为了使用 dropEffect 属性,必须在放置目标的 ondragenter 事件处理程序中设置它
effectAllowed 属性表示对被拖动元素是否允许 dropEffect。也就是说,只有同时设置 effectAllowed,dropEffect 属性才会生效。这个属性有如下几个可能的值:
- uninitialized:没有给被拖动元素设置动作
- none:被拖动元素上没有允许的操作
- copy:只允许 copy 这种 dropEffect
- link:只允许 link 这种 dropEffect
- move:只允许 move 这种 dropEffect
- copyLink:允许 copy 和 link 两种 dropEffect
- copyMove:允许 copy 和 move 两种 dropEffect
- linkMove:允许 link 和 move 两种 dropEffect
- all:允许所有 dropEffect
必须在 ondragstart 事件处理程序中设置这个属性
其他成员
HTML5 规范还为 dataTransfer 对象定义了下列方法:
- addElement(element):为拖动操作添加元素。这纯粹是为了传输数据,不会影响拖动操作的外观
- clearData(format):清除以特定格式存储的数据
- setDragImage(element, x, y):允许指定拖动发生时显示在光标下面的图片。这个方法接收三个参数:要显示的 HTML 元素及标识光标位置的图片上的 x 和 y 坐标。这里的 HTML 元素可以是一张图片,此时显示图片;也可以是其他任何元素,此时显示渲染后的元素
- types:当前存储的数据类型列表。这个集合类似数组,以字符串形式保存数据类型,比如’text’
补充:MIME类型
媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型)是一种标准,用来表示文档、文件或字节流的性质和格式。它在IETFRFC 6838中进行了定义和标准化
MIME 有类型与子类型两个字符串中间用 / 分隔而组成。不允许出现空格,对大小写不敏感,但是传统写法都是小写
类型 | 描述 | 典型示例 |
---|---|---|
text | 表明文件是普通文本,理论上是人类可读 | text/plain,text/html,text/css,text/javascript |
image | 表明是某种图像,不包括视频。(动态图比如gif也使用 image 类型) | image/gif,image/png,image/jpeg,image/x-icon,image/bmp |
audio | 表明是某种音频文件 | audio/midi,audio/mpeg,audio/ogg,audio/wav |
video | 表明是某种视频文件 | video/webm,video/ogg |
application | 表明是某种二进制数据 | application/octet-stream,application/pkcs12,application/vnd.mspowerpoint,application/pdf |
对于 text 文件类型若没有特定的子类型,就使用 text/plain。类似的,二进制文件没有特定或已知的子类型,就使用 application/octet-stream
Page Visibility API
该 API 旨在为开发者提供页面对用户是否可见的信息,由3部分构成:
- document.visibilityState 只读。返回文档的可见性。有以下三个值:
- visible 此时页面在前台标签页
- hidden 页面对用户不可见,即文档在后台标签页或浏览器最小化了,或者操作系统处于锁屏状态
- prerender 页面此时正在渲染中,因此是不可见的。文档只能从此状态开始,永远不能从其他值变为此状态
- visibilitychange 事件,该事件会在文档从隐藏变可见(或反之)时触发
- document.hidden 布尔值,表示页面是否隐藏。这个值是为了向后兼容才存在的,应优先使用 document.visibilityState 检测页面可见性