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
2
3
4
5
6
7
8
console.log(new Blob(['foo']))
// Blob { size: 3, type: '' }

console.log(new Blob(['{"a": "b"}'], { type: 'application/json' }))
// { size: 10, type: 'application/json' }

console.log(new Blob(['<p>Foo</p>', '<p>Bar</p>'], { type: 'text/html' }))
// { size: 20, type: 'text/html' }

Blob 对象有一个 size 属性和一个 type 属性,还有一个 slice() 方法用于切分数据。另外也可以使用 FileReader 从 Blob 中读取数据

1
2
3
4
……
const files = event.target.files
const blob = new Blob([files[0]]).slice(0, 32)
// blob 为 files[0] 的前 32 位字节

只读取部分文件可以节省时间,特别是在只需要数据特定部分比如文件头的时候

对象 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
2
3
if(audio.canPlayType("audio/mpeg")){
…………
}

在只给 canPlayType() 提供一个 MIME 类型的情况下,最可能返回的是 maybe 和空字符串。这是因为文件实际上只是一个包装音频和视频数据的容器,而真正决定文件是否可以播放的是编码。在同时提供 MIME 类型和编解码器的情况下,返回值的可能性会提高到 probably

1
2
3
4
5
6
7
8
9
let audio = document.querySelector('.audio-player');
// 返回值可能是 maybe
if(audio.canPlayType('audio/mpeg')) {
…………
}
// 可能是 probably
if(audio.canPlayType('audio/ogg; codecs="vorbis"')) {
…………
}

注意:编解码器必须放到引号中。同样,也可以在视频元素上使用 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 检测页面可见性

Streams API