FileReaderSync - Web API 接口参考

FileReaderSync
==============

`FileReaderSync`接口允许以同步的方式读取`File`或`Blob`对象中的内容。

该接口只在workers里可用,因为在主线程里进行同步 I/O 操作可能会阻塞用户界面。

方法概述
----
```

ArrayBuffer readAsArrayBuffer(Blob blob);
DOMString readAsBinaryString(Blob blob);
DOMString readAsText(Blob blob, optional DOMString encoding);
DOMString readAsDataURL(Blob blob);
```

属性
--

该接口没有任何属性。

方法
--

### readAsArrayBuffer()

该方法可以读取指定的 `Blob` 或者 `File` 对象中的内容。当读取完毕后，返回一个 `ArrayBuffer` 对象，里面包含了被读取文件的内容数据。如果在读取过程中发生了错误，则会抛出相关的异常。
```

ArrayBuffer readAsArrayBuffer(
  in Blob blob
);
```

#### 参数

`blob`

将要被读取内容的`Blob` 或 `File` 对象。

#### 返回值

一个 `ArrayBuffer` 对象，包含了被读取文件的内容。

#### 异常

该方法可能引发下述异常：

`NotFoundError`

当`Blob`或`File`对象指代的资源无法找到时，触发该异常。比如，该资源已被删除的情况下。

`SecurityError`

当检测到下述几种问题情形时触发该异常：

* 资源已被第三方修改；
* 同时在进行多个读取操作；
* 资源的安全级别过高，不允许浏览器进行操作（比如系统文件）。

`NotReadableError`

当资源由于权限问题不能被读取时触发该异常。比如并发锁。

`EncodingError`

当资源是一个 data URL，并且超过了浏览器的限制大小时触发该异常。

### readAsBinaryString()
已弃用

该方法可以读取指定的 `Blob` 或者 `File`对象的内容。当读取完毕后，返回一个`DOMString`对象，里面包含了被读取文件的二进制数据。如果在读取过程中发生了错误，则会抛出相关的异常。

**备注：** 该方法已被废弃，应该使用`readAsArrayBuffer()`来替代。
```

String readAsBinaryString(
  in Blob blob
);
```

#### 参数

`blob`

将要被读取内容的`Blob` 或 `File` 对象。

#### 返回值

`一个``DOMString`对象，包含了从资源中读取的二进制数据。

#### 异常

该方法可能引发下述异常：

`NotFoundError`

当`Blob`或`File`对象指代的资源无法找到时，触发该异常。比如，该资源已被删除的情况下。

`SecurityError`

当检测到下述几种问题情形时触发该异常：

* 资源已被第三方修改；
* 同时在进行多个读取操作；
* 资源的安全级别过高，不允许浏览器进行操作（比如系统文件）。

`NotReadableError`

当资源由于权限问题不能被读取时触发该异常（比如并发锁）。

`EncodingError`

当资源是一个 data URL，并且超过了浏览器的限制大小时触发该异常。

### readAsText()

该方法可以读取指定的 `Blob` 或者 `File`对象的内容。当读取完毕后，返回一个`DOMString`对象，里面包含了被读取文件的内容数据。可选参数 **`encoding`** 用来表示文件的编码类型，如果省略该参数，则该方法会使用一些算法自动检测文件的编码类型。如果在读取过程中发生了错误，则会抛出相关的异常。
```

String readAsText(
  in Blob blob,
  in DOMString encoding 可选
);
```

#### 参数

`blob`

将要被读取内容的`Blob` 或 `File` 对象。

`encoding`

可选参数，表示被读取文件的编码类型，比如**GBK** 或者 **UTF-8。**

#### 返回值

一个`DOMString`对象，包含了被读取文件的内容。

#### 异常

该方法可能引发下述异常：

`NotFoundError`

当`Blob`或`File`对象指代的资源无法找到时，触发该异常。比如，该资源已被删除的情况下。

`SecurityError`

当检测到下述几种问题情形时触发该异常：

* 资源已被第三方修改；
* 同时在进行多个读取操作；
* 资源的安全级别过高，不允许浏览器进行操作。（比如系统文件）。

`NotReadableError`

当资源由于权限问题不能被读取时触发该异常（比如并发锁）。

### readAsDataURL()

该方法可以读取指定的 `Blob` 或者 `File`对象的内容。当读取完毕后，返回一个 Data URL 格式的`DOMString`对象，里面包含了被读取文件的内容数据。如果在读取过程中发生了错误，则会抛出相关的异常。
```

String readAsDataURL(
  in Blob file
);
```

#### 参数

`blob`

将要被读取内容的`Blob` 或 `File` 对象。

#### 返回值

`一个``DOMString`对象，data URL 格式，包含了被读取文件的内容。

#### 异常

该方法可能引发下述异常：

`NotFoundError`

当`Blob`或`File`对象指代的资源无法找到时，触发该异常。比如，该资源已被删除的情况下。

`SecurityError`

当检测到下述几种问题情形时触发该异常：

* 资源已被第三方修改；
* 同时在进行多个读取操作；
* 资源的安全级别过高，不允许浏览器进行操作（比如系统文件）。

`NotReadableError`

当资源由于权限问题不能被读取时触发该异常（比如并发锁）。

`EncodingError`

当资源是一个 data URL，并且超过了浏览器的限制大小时触发该异常。

规范
--

| Specification |
| --- |
| File API # FileReaderSync |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `FileReader`
* `Blob`
* `File`


DOMHighResTimeStamp - Web API 接口参考

DOMHighResTimeStamp
===================

**`DOMHighResTimeStamp`** 是一个 double 类型，用于存储毫秒级的时间值。这种类型可以用来描述离散的时间点或者一段时间（两个离散时间点之间的时间差）。

这种基于毫秒精度的时间，应该精确到 5 微秒级别，其数值的小数部分代表了一个毫秒的小数（也就是微秒）。但是，如果浏览器不能提供精确到 5 微秒的时间值 (例如，由于硬件或软件的限制)，浏览器可以在表示一个以毫秒为单位的时间值时，精确到毫秒级别。同时要注意，在下一节中提到，由浏览器首选项控制的**降低时间精度**，是为了防止时序攻击和记录指纹。

此外，如果用户代理运行所在的设备或操作系统不具备精确到微秒级别的时钟，那么他们只能精确到毫秒。

降低时间精度
------

为了提供对抗时序攻击和记录指纹的保护措施，时间戳可能会四舍五入，这取决于浏览器设置。在火狐浏览器中，`privacy.reduceTimerPrecision` 首选项默认被启用，并且在火狐浏览器 59 版本中，它的默认值是 20 微秒。在火狐浏览器 60 版本中，这个默认值将是 2 毫秒。

```js
// reduced time precision (2ms) in Firefox 60
event.timeStamp;
// 1519211809934
// 1519211810362
// 1519211811670
// ...

// reduced time precision with `privacy.resistFingerprinting` enabled
event.timeStamp;
// 1519129853500
// 1519129858900
// 1519129864400
// ...
```

在火狐浏览器中，你也可以启用 `privacy.resistFingerprinting`，这使得时间戳的精度变成 100 毫秒或 `privacy.resistFingerprinting.reduceTimerPrecision.microseconds` 的值，以较大者为准。

属性
--

*这个类型没有属性。它是一个双精度浮点数。*

### 值

`DOMHighResTimeStamp` 的值是一个双精度浮点数，它描述了两个时间点之间的经过的毫秒数（可以精确到 5 微秒，如果设备支持）。开始时间可以是由网站或 app 中的脚本定义的一个特定时间 T，也可以是**时间源**。

#### 时间源

**时间源**是一个可以被认定为当前文档生命周期的开始节点的标准时间，计算方法如下：

* 如果脚本的 global object 是 `Window`，则时间源的确定方式如下：
    + 如果当前 `Document` 是中加载的第一个 `Window`，则**时间源**是创建浏览器上下文的时间。
    + 如果处于卸载窗口中已加载的先前文档的过程中，一个确认对话框会显示出来，让用户确认是否离开前一页，则**时间源**是用户确认导航到新页面的这个时间，这一点是被认同的。
    + 如果以上方式都不能确定**时间源**，那么**时间源**是创建窗口中当前 `Document` 的导航发生的时机。
* 如果脚本中的全局对象是 `WorkerGlobalScope` (en-US)（意味着，该脚本以 web worker 的形式运行），则**时间源**是这个 worker 被创建的时刻。
* 在所有其他情况下，**时间源**的值是 undefined。
方法
--

*这个类型没有方法。*

用法说明
----

你可以通过调用 `performance` 的 `now()` 方法来获取当前的时间戳的值（自创建上下文以来经过的时间）。此方法在 `Window` 和 `Worker` 上下文中均可用。

示例
--

如果你需要确定从代码中某处开始经过了多少时间，可以执行以下操作：

```js
const startTime = performance.now();

/\* ... do things for a while ... \*/

const elapsedTime = performance.now() - startTime;
```

执行完毕后，`elapsedTime` 的值是从你在第一行代码记录的时间点开始后经过的毫秒数。

规范
--

#### No specification found

No specification data found for `api.DOMHighResTimestamp`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* Navigation Timing API (en-US)
* Performance.now()
* https://www.w3.org/TR/hr-time/#sec-DOMHighResTimeStamp
* https://www.w3.org/TR/hr-time-2/


CanvasPattern - Web API 接口参考

CanvasPattern
=============

**`CanvasPattern`** 接口表示描述一个模板（基于 image、canvas 或 video）的不透明对象，通过 `CanvasRenderingContext2D.createPattern()` 方法创建。

属性
--

*非透明对象，没有暴露的属性。*

方法
--

*没有继承来的方法。*

`CanvasPattern.setTransform()`

应用 `DOMMatrix` 对模板做线性变换

规范
--

| Specification |
| --- |
| HTML Standard # canvaspattern |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `CanvasRenderingContext2D.createPattern()`
* `<canvas>` 元素及和 canvas 相关接口 `HTMLCanvasElement`


DataTransferItemList - Web API 接口参考

DataTransferItemList
====================

**`DataTransferItemList`** 对象是一组代表被拖动项的`DataTransferItem` 对象的列表。在拖动操作期间，每个`DragEvent` 都有一个 `dataTransfer` 属性，该属性是 `DataTransferItemList`.

该接口没有构造函数

属性
--

`DataTransferItemList.length` 只读

`无符号长整型` ：列表中拖动项的数量。

方法
--

`DataTransferItemList.add()` (en-US)

向拖动项列表中添加新项 (`File`对象或`string`)，该方法返回一个 `DataTransferItem` 对象。

`DataTransferItemList.remove()` (en-US)

根据索引删除拖动项列表中的对象。

`DataTransferItemList.clear()` (en-US)

清空拖动项列表。

`DataTransferItemList.DataTransferItem()` (en-US)

取值方法：返回给定下标的`DataTransferItem`对象。

示例
--

每个方法或属性都有其引用页面，每一个引用页对应也有使用示例。

规范
--

| Specification |
| --- |
| HTML Standard # the-datatransferitemlist-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MediaQueryListEvent - Web API 接口参考

MediaQueryListEvent
===================

`MediaQueryListEvent` 对象存储着发生在 `MediaQueryList` 对象上的变化的信息——作为一个在函数中被 `change` 事件引用的事件对象。

Event

MediaQueryListEvent构造函数
----

`MediaQueryListEvent()`

创建一个新的 `MediaQueryListEvent` 实例。

属性
--

*`MediaQueryListEvent` 接口的属性继承自它的父接口，`Event`。*

`MediaQueryListEvent.matches` (en-US) 只读

 一个布尔值，如果 `document`
 目前匹配媒体查询列表，该值为 `true` ，反之为 `false`。

`MediaQueryListEvent.media` (en-US) 只读

一个字符串，代表着一个序列化后的媒体查询。

方法
--

*`MediaQueryListEvent` 接口的方法继承自它的父接口，`Event`。*

示例
--

```js
var mql = window.matchMedia("(max-width: 600px)");

function screenTest(e) {
  if (e.matches) {
    /\* 视口等于或小于 600 像素 \*/
    para.textContent = "This is a narrow screen — less than 600px wide.";
    document.body.style.backgroundColor = "red";
  } else {
    /\* 视口大于 600 像素 \*/
    para.textContent = "This is a wide screen — more than 600px wide.";
    document.body.style.backgroundColor = "blue";
  }
}

mql.addListener(screenTest);
```

规范
--

| Specification |
| --- |
| CSSOM View Module # the-mediaquerylist-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 媒体查询
* 在代码中使用媒体查询
* `window.matchMedia()`
* `MediaQueryList`


DataTransferItem - Web API 接口参考

DataTransferItem
================

**`DataTransferItem`** 描述了一个拖拽项。在一个拖拽操作\*中，\*每一个 `drag event` 都有一个`dataTransfer` 属性，它包含一个存有拖拽数据的 `list` ，其中每一项都是一个 `DataTransferItem` 。

这个接口没有构造函数。

属性
--

`DataTransferItem.kind` 只读

拖拽项的种类，`string` 或是 `file`。

`DataTransferItem.type` 只读

拖拽项的类型，一般是一个 MIME 类型。

方法
--

`DataTransferItem.getAsFile()`

返回一个关联拖拽项的 `File` 对象（当拖拽项不是一个文件时返回 null）。

`DataTransferItem.getAsString()`

使用拖拽项的字符串作为参数执行指定回调函数。

`DataTransferItem.webkitGetAsEntry()`
非标准

返回一个基于 `FileSystemEntry` (en-US) 的对象来表示文件系统中选中的项目。通常是返回一个`FileSystemFileEntry` 或是 `FileSystemDirectoryEntry` 对象。

例子
--

这个接口所有的属性和方法都有自己的介绍页，请到各自的介绍页中查看示例用法。

规范
--

| Specification |
| --- |
| HTML Standard # the-datatransferitem-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


IdleDeadline - Web API 接口参考

IdleDeadline
============

`IdleDeadline` 接口是在调用 `Window.requestIdleCallback()` 时创建的闲置回调的输入参数的数据类型。它提供了 `timeRemaining()` 方法，用来判断用户代理预计还剩余多少闲置时间；以及 `didTimeout` (en-US) 属性，用来判断当前的回调函数是否因超时而被执行。

想要学习更多有关请求回调工作原理的知识，请参考后台任务协作调度。

实例属性
----

`IdleDeadline.didTimeout` (en-US) 只读

一个布尔值，如果回调是因为超过了设置的超时时间而被执行的，则其值为 `true`。

实例方法
----

`IdleDeadline.timeRemaining()`

返回一个 `DOMHighResTimeStamp`，其为浮点数，用来表示当前闲置周期的预估剩余毫秒数。如果闲置期已经结束，则其值为 0。你的回调函数可以重复调用该函数，以判断目前是否有足够的时间来执行更多的任务。

示例
--

在后台任务协作调度 API 中查看我们的完整示例。

规范
--

| Specification |
| --- |
| requestIdleCallback() Cooperative Scheduling of Background Tasks # the-idledeadline-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 后台任务协作调度 API
* `Window.requestIdleCallback()`
* `Window.cancelIdleCallback()`


Blob - Web API 接口参考

Blob
====

`Blob` 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取，也可以转换成 `ReadableStream` 来用于数据操作。

Blob 表示的不一定是 JavaScript 原生格式的数据。`File` 接口基于 `Blob`，继承了 blob 的功能并将其扩展以支持用户系统上的文件。

使用 blob
-------

要从其他非 blob 对象和数据构造一个 `Blob`，请使用 `Blob()` 构造函数。要创建一个 blob 数据的子集 blob，请使用 `slice()` 方法。要获取用户文件系统上的文件对应的 `Blob` 对象，请参阅 `File` 文档。

接受 `Blob` 对象的 API 也被列在 `File` 文档中。

构造函数
----

`Blob()`

返回一个新创建的 `Blob` 对象，其内容由参数中给定的数组拼接组成。

实例属性
----

`Blob.size` 只读

`Blob` 对象中所包含数据的大小（字节）。

`Blob.type` 只读

一个字符串，表明该 `Blob` 对象所包含数据的 MIME 类型。如果类型未知，则该值为空字符串。

实例方法
----

`Blob.arrayBuffer()`

返回一个 promise，其会兑现一个包含 `Blob` 所有内容的二进制格式的 `ArrayBuffer`。

`Blob.slice()`

返回一个新的 `Blob` 对象，包含了源 `Blob` 对象中指定范围内的数据。

`Blob.stream()`

返回一个能读取 `Blob` 内容的 `ReadableStream`。

`Blob.text()`

返回一个 promise，其会兑现一个包含 `Blob` 所有内容的 UTF-8 格式的字符串。

示例
--

### 创建一个 blob

`Blob()` 构造函数可以通过其他对象创建 blob。例如，用一个 JSON 字符串构造一个 blob：

```js
const obj = { hello: "world" };
const blob = new Blob([JSON.stringify(obj, null, 2)], {
  type: "application/json",
});
```

### 创建一个指向类型化数组的 URL

以下代码创建了一个 JavaScript 类型化数组，并创建一个新的，包含类型化数组中的数据的 `Blob`。然后调用 `URL.createObjectURL()` 方法，将 blob 转换为一个 URL。

#### HTML

```html
<p>
  此示例创建一个类型化数组，其中包含空格以及 A 到 Z 的 ASCII
  字符。然后将其转换为一个对象 URL。并创建一个打开该对象 URL
  的链接。点击这个链接以查看对象 URL 解码后的内容。
</p>
```

#### JavaScript

该示例代码片段的主要片段是 `typedArrayToURL()` 函数，其用于从给定的类型化数组创建一个 `Blob`，并返回该 `Blob` 的对象 URL。将数据转换为对象 URL 后，可通过多种方式使用，包括：作为 `<img>` 元素 `src` 属性的值（当然，假设给定的数据包含了一张图片）。

```js
function showViewLiveResultButton() {
  if (window.self !== window.top) {
    // 如果当前文档是否在一个 frame 中，则
    // 确保让用户在新的标签页或窗口中打开它。
    // 否则，此示例将无法正常演示。
    const p = document.querySelector("p");
    p.textContent = "";
    const button = document.createElement("button");
    button.textContent = "查看上面示例代码的渲染结果";
    p.append(button);
    button.addEventListener("click", () => window.open(location.href));
    return true;
  }
  return false;
}

if (!showViewLiveResultButton()) {
  function typedArrayToURL(typedArray, mimeType) {
    return URL.createObjectURL(
      new Blob([typedArray.buffer], { type: mimeType }),
    );
  }
  const bytes = new Uint8Array(59);

  for (let i = 0; i < 59; i++) {
    bytes[i] = 32 + i;
  }

  const url = typedArrayToURL(bytes, "text/plain");

  const link = document.createElement("a");
  link.href = url;
  link.innerText = "打开这个数组的 URL";

  document.body.appendChild(link);
}
```

#### 结果

### 从 blob 中提取数据

一种从 `Blob` 中读取内容的方法是使用 `FileReader`。以下代码将 `Blob` 的内容作为类型化数组读取：

```js
const reader = new FileReader();
reader.addEventListener("loadend", () => {
  // reader.result 包含被转化为类型化数组的 blob 中的内容
});
reader.readAsArrayBuffer(blob);
```

另一种读取 `Blob` 中内容的方式是使用 `Response` 对象。下述代码将 `Blob` 中的内容读取为文本：

```js
const text = await new Response(blob).text();
```

或者，也可以使用 `Blob.text()`：

```js
const text = await blob.text();
```

通过使用 `FileReader` 的其他方法可以把 Blob 读取为字符串或者数据 URL。

规范
--

| Specification |
| --- |
| File API # blob-section |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `FileReader`
* `File`
* `URL.createObjectURL`
* 在 web 应用程序中使用文件


ChannelMergerNode - Web API 接口参考

ChannelMergerNode
=================

`ChannelMergerNode` 接口，经常与其对应的 `ChannelSplitterNode` (en-US) 接口一起使用，将不同的单声道输入重新组合成单个输出。每个输入用于填充输出的一个通道。这对于分别访问每个通道非常有用，例如，执行通道混合时，必须在每个信道上单独控制增益。

![](/zh-CN/docs/Web/API/ChannelMergerNode/webaudiomerger.png)

如果 `ChannelMergerNode` 用于一个单一输出，但输入数量与用于合并的信道数量相同；输入的数量被定义为其构造函数的参数及对 `AudioContext.createChannelMerger` 的调用。如果没有给出值，则为默认值 `6`。

使用 `ChannelMergerNode`，可以创建比渲染硬件能处理的更多的通道输出。在这种情况下，当信号发送至 `AudioContext.listener` 对象时，额外的信道将被忽略。

|  |  |
| --- | --- |
| 输入数量 | 变量; 默认为 `6`. |
| 输出数量 | `1` |
| 通道计数模式 | `"max"` |
| 通道数量 | `2` (不在默认计数模式下使用) |
| 频道解释 | `"speakers"` |

构造函数
----

`ChannelMergerNode()`

生成一个新的 `ChannelMergerNode` 对象实例。

属性
--

*没有具体属性；从其父级继承属性，`AudioNode`。*

方法
--

*没有具体方法；从其父级继承方法，`AudioNode`。*

例子
--

参见 `BaseAudioContext.createChannelMerger()` 以获取示例代码。

规格
--

| Specification |
| --- |
| Web Audio API # ChannelMergerNode |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* Using the Web Audio API (en-US)


WebCodecs API - Web API 接口参考

WebCodecs API
=============

**WebCodecs API** 为 web 开发者提供了对视频流的单个帧和音频数据块的底层访问能力。这对于那些需要完全控制媒体处理方式的 web 应用程序非常有用。例如，视频或音频编辑器，以及视频会议。

概念和用法
-----

许多 Web API 在内部都使用了媒体编码器。例如，`Web Audio API`，以及 `WebRTC API`。然而，这些 API 不允许开发者处理视频流的单个帧和未合成的编码音频块或视频块。

Web 开发者通常使用 WebAssembly 来绕过这一限制，并在浏览器中使用媒体编解码器。然而，这需要额外的带宽来下载浏览器中已经存在的编解码器，降低了性能和能效，并增加了额外的开发成本。

WebCodecs API 提供了对浏览器中已存在的编解码器的访问能力。它可以访问原始视频帧、音频数据块、图像解码器、音频和视频的编码器及解码器

接口
--

`AudioDecoder` (en-US)

解码 `EncodedAudioChunk` (en-US) 对象。

`VideoDecoder` (en-US)

解码 `EncodedVideoChunk` (en-US) 对象。

`AudioEncoder` (en-US)

编码 `AudioData` (en-US) 对象。

`VideoEncoder` (en-US)

编码 `VideoFrame` (en-US) 对象。

`EncodedAudioChunk` (en-US)

表示特定于编解码器的编码音频字节。

`EncodedVideoChunk` (en-US)

表示特定于编解码器的编码视频字节。

`AudioData` (en-US)

表示未编码的音频数据。

`VideoFrame` (en-US)

表示一帧未编码的视频数据。

`VideoColorSpace` (en-US)

表示视频帧的颜色空间。

`ImageDecoder` (en-US)

解包和解码图像数据，允许访问动画图像中的帧序列。

`ImageTrackList` (en-US)

表示图像中可用的轨道列表。

`ImageTrack` (en-US)

表示单个图像轨道。

示例
--

在下面这个例子中，获取从 `MediaStreamTrackProcessor` (en-US) 中返回的帧，然后对他们进行编码。在文章使用 WebCodec 处理视频查看完整示例并了解更多细节。

```js
let frame_counter = 0;
const track = stream.getVideoTracks()[0];
const media_processor = new MediaStreamTrackProcessor(track);
const reader = media_processor.readable.getReader();
while (true) {
  const result = await reader.read();
  if (result.done) break;
  let frame = result.value;
  if (encoder.encodeQueueSize > 2) {
    // Too many frames in flight, encoder is overwhelmed
    // let's drop this frame.
    frame.close();
  } else {
    frame_counter++;
    const insert_keyframe = frame_counter % 150 === 0;
    encoder.encode(frame, { keyFrame: insert_keyframe });
    frame.close();
  }
}
```

参考
--

* 使用 WebCodec 处理视频


SVGGraphicsElement - Web API 接口参考

SVGGraphicsElement
==================

**`SVGGraphicsElement`** 接口表示 SVG 元素，其主要目的是将图形直接渲染到组中。

**备注：** 该接口是 SVG 2 中引入的，它取代了 SVG 1.1 中的`SVGLocatable`和`SVGTransformable`接口。

属性
--

此接口还从其父接口`SVGElement`继承属性

`SVGGraphicsElement.transform` 只读

一个`SVGAnimatedTransformList` (en-US)反映给定元素的`transform`属性的计算值及其对应的`transform`属性。

方法
--

此接口还从其父方法`SVGElement`继承方法。

`SVGGraphicsElement.getBBox()`

返回一个`DOMRect`，它表示当前元素的计算出的边界框。

`SVGGraphicsElement.getCTM()`

返回一个`DOMMatrix`，代表将当前元素的坐标系转换为其 SVG 视口的坐标系的矩阵。

`SVGGraphicsElement.getScreenCTM()`

返回一个`DOMMatrix`代表表示将当前元素的坐标系转换为 SVG 文档片段的 SVG 视口的坐标系的矩阵。

规范
--

| Specification |
| --- |
| Scalable Vector Graphics (SVG) 2 # InterfaceSVGGraphicsElement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


self.createImageBitmap() - Web API 接口参考

self.createImageBitmap()
========================

**`createImageBitmap`** 方法存在 windows 和 workers 中。它接受各种不同的图像来源，并返回一个`Promise` (en-US), resolve 为`ImageBitmap`. 可选地参数，图像被剪裁成自（sx，sy）且宽度为 sw，高度为 sh 的像素的矩形。

Syntax
------
```

createImageBitmap(image[, options]).then(function(response) { ... });
createImageBitmap(image, sx, sy, sw, sh[, options]).then(function(response) { ... });
```

### Parameters

`image`

一个图像源，可以是一个 `<img>`, SVG `<image>`, `<video>`, `<canvas>`, `HTMLImageElement`, `SVGImageElement` (en-US), `HTMLVideoElement`, `HTMLCanvasElement`, `Blob`, `ImageData`, `ImageBitmap`, 或 `OffscreenCanvas` 对象。

`sx`

裁剪点 x 坐标。

`sy`

裁剪点 y 坐标。

`sw`

裁剪宽度，值可为负数。

`sh`

裁剪高度，值可为负数。

options 可选

为其设置选项的对象。可用的选项是：

* `imageOrientation`: 指示图像是按原样呈现还是垂直翻转。`none` (默认不翻转) 或 `flipY`.
* `premultiplyAlpha`: 指示位图颜色通道由 alpha 通道预乘。选择其一：`none`, `premultiply`, 或 `default` (默认).
* `colorSpaceConversion`: 指示图像是否使用色彩空间转换进行解码。`none` 或 `default` (默认). The value `default` indicates that implementation-specific behavior is used.
* `resizeWidth`: 指示新宽度的长整数。
* `resizeHeight`: 指示新高度的长整数。
* `resizeQuality`: 指定图像缩放算法。选择其一`pixelated`, `low` (默认), `medium`, 或 `high`.

### Return value

返回一个解决 ImageBitmap 的`Promise` (en-US) ，当 Promise 成功时 resolves 接收一个包含所得到的矩形的位图数据`ImageBitmap`。

Example
-------

```js
var canvas = document.getElementById("myCanvas"),
  ctx = canvas.getContext("2d"),
  image = new Image();

image.onload = function () {
  Promise.all([
    createImageBitmap(this, 0, 0, 32, 32),
    createImageBitmap(this, 32, 0, 32, 32),
  ]).then(function (sprites) {
    ctx.drawImage(sprites[0], 0, 0);
    ctx.drawImage(sprites[1], 32, 32);
  });
};

image.src = "sprites.png";
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-createimagebitmap-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `CanvasRenderingContext2D.drawImage()`
* `ImageData`


PushManager - Web API 接口参考

PushManager
===========

Push API 的`PushManager`接口提供了从第三方服务器接收消息通知的能力。

可以通过 ServiceWorkerRegistration.pushManager 属性获得

**备注：** 这个属性替代了已被废弃的`PushRegistrationManager`

Properties
----------

*None.*

Methods
-------

`PushManager.getSubscription()`

用于获取已经存在的 push 订阅。返回一个`Promise`，这个`Promise`包装着 push 订阅信息的`PushSubscription` (en-US)对象。如果没有已经存在的订阅，则返回`null`。

`PushManager.permissionState()` (en-US)

返回一个`Promise`，标识这当前`PushManager`的权限状态，只能是 `'granted'`，`'denied'` ，`'prompt'` 中的一种。

`PushManager.subscribe()`

向 push 服务器（即第三方 push server）发起订阅。返回一个`Promise`，这个`Promise`包装着 push 订阅信息的`PushSubscription` (en-US)对象。如果当前的 service worke 没有已经存在的订阅，则会创建一个新的 push 订阅。

### 已废弃的方法

`PushManager.hasPermission()` (en-US)
已弃用

（已废弃）返回一个`Promise`，标识着该 webapp 的`PushPermissionStatus`状态，该状态只能是 `'granted'`，`'denied'` ，`'default'` 中的一种。目前已经被`PushManager.permissionState()` (en-US)取代。

`PushManager.register()` (en-US)
已弃用

（已废弃）发起注册 push 订阅。目前已经被`PushManager.subscribe()`取代。

`PushManager.registrations()` (en-US)
已弃用

（已废弃）返回已存在的 push 订阅信息。目前已经被`PushManager.getSubscription()`取代。

`PushManager.unregister()` (en-US)
已弃用

（已废弃）取消注册并删除指定的注册信息。在更新后的 API 中，请使用 `PushSubscription.unsubscribe()` (en-US)方法取消注册。

示例
--

```js
this.onpush = function (event) {
  console.log(event.data);
  // 这里我们可以将数据写入 IndexedDB，发送给其他 window 对象，或者显示一个通知
};

navigator.serviceWorker
  .register("serviceworker.js")
  .then(function (serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe().then(
      function (pushSubscription) {
        console.log(pushSubscription.subscriptionId);
        console.log(pushSubscription.endpoint);
        // 现在我们已经获取到了服务器需要的 push 订阅信息，我们可以使用 XHR 将它们发送给服务器
      },
      function (error) {
        // 在开发环境下打印错误是很有帮助的。在生产环境下，将错误上报到服务器也是十分必要的
        console.log(error);
      },
    );
  });
```

Specifications
--------------

| Specification |
| --- |
| Push API # pushmanager-interface |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using the Push API (en-US)
* Push API
* Service Worker API


WritableStreamDefaultWriter - Web API 接口参考

WritableStreamDefaultWriter
===========================

Stream API 的 **`WritableStreamDefaultWriter`** 接口是由 `WritableStream.getWriter()` 返回的对象，并且一旦创建就会将 writer 锁定到 `WritableStream`，确保没有其他流可以写入底层 sink。

构造函数
----

`WritableStreamDefaultWriter()`

创建一个新的 `WritableStreamDefaultWriter` 对象实例。

实例属性
----

`WritableStreamDefaultWriter.closed`只读

允许你编写当流结束时执行的代码。返回一个流关闭时兑现的 promise，或者在抛出错误或者 writer 的锁释放时被拒绝。

`WritableStreamDefaultWriter.desiredSize`只读

返回填充满流的内部队列所需要的大小。

`WritableStreamDefaultWriter.ready`只读

返回一个 `Promise`，当流填充内部队列的所需大小从非正数变为正数时兑现，表明它不再应用背压。

实例方法
----

`WritableStreamDefaultWriter.abort()`

中止流，表示生产者不能再向流写入数据（会立刻返回一个错误状态），并丢弃所有已入队的数据。

`WritableStreamDefaultWriter.close()`

关闭关联的可写流。

`WritableStreamDefaultWriter.releaseLock()`

释放 writer 对相应流的锁定。释放锁后，writer 将不再处于锁定状态。如果释放锁时关联流出错，writer 随后也会以同样的方式发生错误；此外，writer 将关闭。

`WritableStreamDefaultWriter.write()`

将传递的数据块写入 `WritableStream` 和它的底层接收器，然后返回一个 `Promise`，promise 的状态由写入操作是否成功来决定。

示例
--

下面的例子说明了这个接口的几个功能。它展示了使用自定义接收器和由 API 提供的队列策略创建的 `WritableStream`。然后它调用一个 `sendMessage()` 的函数，传递新创建的流和一个字符串。在这个函数内部，它调用流的 `getWriter()` 方法，该方法返回一个 `WritableStreamDefaultWriter` 实例。`forEach()` 用于将字符串的每个分块写入流。最后，`write()` 和 `close()` 方法都会返回 promise，promise 的状态由对应的操作是否成功来决定。

```js
const list = document.querySelector("ul");
function sendMessage(message, writableStream) {
  // defaultWriter is of type WritableStreamDefaultWriter
  const defaultWriter = writableStream.getWriter();
  const encoder = new TextEncoder();
  const encoded = encoder.encode(message, { stream: true });
  encoded.forEach((chunk) => {
    defaultWriter.ready
      .then(() => {
        return defaultWriter.write(chunk);
      })
      .then(() => {
        console.log("Chunk written to sink.");
      })
      .catch((err) => {
        console.log("Chunk error:", err);
      });
  });
  // Call ready again to ensure that all chunks are written
  // before closing the writer.
  defaultWriter.ready
    .then(() => {
      defaultWriter.close();
    })
    .then(() => {
      console.log("All chunks written");
    })
    .catch((err) => {
      console.log("Stream error:", err);
    });
}
const decoder = new TextDecoder("utf-8");
const queuingStrategy = new CountQueuingStrategy({ highWaterMark: 1 });
let result = "";
const writableStream = new WritableStream(
  {
    // Implement the sink
    write(chunk) {
      return new Promise((resolve, reject) => {
        var buffer = new ArrayBuffer(1);
        var view = new Uint8Array(buffer);
        view[0] = chunk;
        var decoded = decoder.decode(view, { stream: true });
        var listItem = document.createElement("li");
        listItem.textContent = "Chunk decoded: " + decoded;
        list.appendChild(listItem);
        result += decoded;
        resolve();
      });
    },
    close() {
      var listItem = document.createElement("li");
      listItem.textContent = "[MESSAGE RECEIVED] " + result;
      list.appendChild(listItem);
    },
    abort(err) {
      console.log("Sink error:", err);
    },
  },
  queuingStrategy,
);
sendMessage("Hello, world.", writableStream);
```

你可以在我们的简单的 writer 示例找到完整代码。

规范
--

| Specification |
| --- |
| Streams Standard # default-writer-class |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


BiquadFilterNode - Web API 接口参考

BiquadFilterNode
================

`BiquadFilterNode` 接口表示一个简单低阶滤波器（双二阶滤波器），通过 `AudioContext.createBiquadFilter()` 方法创建。它是一个能表示不同类型的过滤器，声调控制设备，图形均衡器的 `AudioNode`。一个`BiquadFilterNode`（双二阶滤波器）总是恰好有一个输入和一个输出。

|  |  |
| --- | --- |
| Number of inputs | `1` |
| Number of outputs | `1` |
| Channel count mode | `"max"` |
| Channel count | `2` (not used in the default count mode) |
| Channel interpretation | `"speakers"` |

属性
--

*继承属性自父级的* *`AudioNode`*.

`BiquadFilterNode.frequency` (en-US)

Is an a-rate `AudioParam`, a double representing a frequency in the current filtering algorithm measured in hertz (Hz).

`BiquadFilterNode.detune` (en-US)

Is an a-rate `AudioParam` representing detuning of the frequency in cents.

`BiquadFilterNode.Q` (en-US)

Is an a-rate `AudioParam`, a double representing a Q factor, or *quality factor*.

`BiquadFilterNode.gain` (en-US) 只读

Is an a-rate `AudioParam`, a double representing the gain used in the current filtering algorithm.

`BiquadFilterNode.type` (en-US)

节点实现定义不同过滤算法的一个字符串值。

| `type` | Description | `frequency` | `Q` | `gain` |
| --- | --- | --- | --- | --- |
| `lowpass` | Standard second-order resonant lowpass filter with 12dB/octave rolloff. Frequencies below the cutoff pass through; frequencies above it are attenuated. | The cutoff frequency. | Indicates how peaked the frequency is around the cutoff. The greater the value is, the greater is the peak. | *Not used* |
| `highpass` | Standard second-order resonant highpass filter with 12dB/octave rolloff. Frequencies below the cutoff are attenuated; frequencies above it pass through. | The cutoff frequency. | Indicates how peaked the frequency is around the cutoff. The greater the value, the greater the peak. | *Not used* |
| `bandpass` | Standard second-order bandpass filter. Frequencies outside the given range of frequencies are attenuated; the frequencies inside it pass through. | The center of the range of frequencies. | Controls the width of the frequency band. The greater the `Q` value, the smaller the frequency band. | *Not used* |
| `lowshelf` | Standard second-order lowshelf filer. Frequencies lower than the frequency get a boost, or an attenuation; frequencies over it are unchanged. | The upper limit of the frequencies getting a boost or an attenuation. | *Not used* | The boost, in dB, to be applied; if negative, it will be an attenuation. |
| `highshelf` | Standard second-order highshelf filer. Frequencies higher than the frequency get a boost or an attenuation; frequencies lower than it are unchanged. | The lower limit of the frequencies getting a boost or an attenuation. | *Not used* | The boost, in dB, to be applied; if negative, it will be an attenuation. |
| `peaking` | Frequencies inside the range get a boost or an attenuation; frequencies outside it are unchanged. | The middle of the frequency range getting a boost or an attenuation. | Controls the width of the frequency band. The greater the `Q` value, the smaller the frequency band. | The boost, in dB, to be applied; if negative, it will be an attenuation. |
| `notch` | Standard notch filter, also called a *band-stop* or *band-rejection* filter. It is the opposite of a bandpass filter: frequencies outside the give range of frequencies pass through; frequencies inside it are attenuated. | The center of the range of frequencies. | Controls the width of the frequency band. The greater the `Q` value, the smaller the frequency band. | *Not used* |
| `allpass` | Standard second-order allpass filter. It lets all frequencies through, but changes the phase-relationship between the various frequencies. | The frequency with the maximal group delay, that is, the frequency where the center of the phase transition occurs. | Controls how sharp the transition is at the medium frequency. The larger this parameter is, the sharper and larger the transition will be. | *Not used* |

方法
--

*继承方法自父级的 `AudioNode`*.

`BiquadFilterNode.getFrequencyResponse()` (en-US)

From the current filter parameter settings this method calculates the frequency response for frequencies specified in the provided array of frequencies.

示例
--

参见 `AudioContext.createBiquadFilter` 以获取示例代码，其中展示了如何使用 `AudioContext` 创建一个 Biquad 滤波器节点。

规范
--

| Specification |
| --- |
| Web Audio API # BiquadFilterNode |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* Using the Web Audio API (en-US)


Encoding API - Web API 接口参考

Encoding API
============

**Encoding API** 提供了一种机制来处理各种字符编码文本，包括传统的非 UTF-8 编码。

API 提供了四个接口：`TextDecoder`、`TextEncoder`、`TextDecoderStream` 和 `TextEncoderStream`。

**备注：** 此特性在 Web Worker 中可用

接口
--

* `TextDecoder`
* `TextEncoder`
* `TextDecoderStream`
* `TextEncoderStream`
规范
--

| Specification |
| --- |
| Encoding Standard # interface-textdecoder |
| Encoding Standard # interface-textencoder |
| Encoding Standard # interface-textencoderstream |
| Encoding Standard # interface-textdecoderstream |

浏览器兼容性
------

### api.TextDecoder

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TextEncoder

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TextEncoderStream

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TextDecoderStream

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 一个 shim，允许在不支持的浏览器中使用这个接口。


Force Touch events - Web API 接口参考

Force Touch events
==================

**非标准:** 该特性是非标准的，请尽量不要在生产环境中使用它！

**Force Touch events** are a proprietary, Apple-specific feature which makes possible (where supported by the input hardware) new interactions based on how hard the user clicks or presses down on the touchscreen or trackpad.

事件
--

`webkitmouseforcewillbegin` (en-US)
非标准

This event is fired before the `mousedown` event. Its main use is that it can be `Event.preventDefault()`ed.

`webkitmouseforcedown` (en-US)
非标准

This event is fired after the `mousedown` event as soon as sufficient pressure has been applied for it to qualify as a "force click".

`webkitmouseforceup` (en-US)
非标准

This event is fired after the `webkitmouseforcedown` (en-US) event as soon as the pressure has been reduced sufficiently to end the "force click".

`webkitmouseforcechanged` (en-US)
非标准

This event is fired each time the amount of pressure changes. This event first fires after the `mousedown` event and stops firing before the `mouseup` event.

事件属性
----

The following property is known to be available on the `webkitmouseforcewillbegin` (en-US), `mousedown`, `webkitmouseforcechanged` (en-US), `webkitmouseforcedown` (en-US), `webkitmouseforceup` (en-US), `mousemove`, and `mouseup` event objects:

`MouseEvent.webkitForce` (en-US)
非标准
 只读

当前施加于触控板/触摸屏的压力大小

常量
--

这些常数对于确定由 `MouseEvent.webkitForce` (en-US) 指示的压力的相对强度是有用的：

`MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN` (en-US)
非标准
 只读

正常点击所需的最小力量

`MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN` (en-US)
非标准
 只读

强制点击所需的最小力量

规范
--

\*不是任何规格的一部分。\*苹果在 Mac 开发者图书馆有一个描述。


WebGLFramebuffer - Web API 接口参考

WebGLFramebuffer
================

**WebGLFramebuffer** 接口时 WebGL API 的一部分，它提供了一个缓冲区的集合，这些缓冲区可以作为一个整体用作渲染操作的目标缓冲区。

摘要
--

`WebGLFramebuffer` 对象的内容不能直接访问，因此该对象没有定义任何用于操作其自身内容的方法和属性。需要使用 `WebGLFramebuffer` 对象时，请使用 `WebGLRenderingContext` 对象的以下方法：

* `WebGLRenderingContext.bindFramebuffer()`
* `WebGLRenderingContext.createFramebuffer()`
* `WebGLRenderingContext.deleteFramebuffer()`
* `WebGLRenderingContext.isFramebuffer()` (en-US)
示例
--

### 创建一个帧缓冲

```js
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
var buffer = gl.createFramebuffer();
```

规范
--

| Specification |
| --- |
| WebGL Specification # 5.5 |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `WebGLRenderingContext.bindFramebuffer()`
* `WebGLRenderingContext.createFramebuffer()`
* `WebGLRenderingContext.deleteFramebuffer()`
* `WebGLRenderingContext.isFramebuffer()` (en-US)
* 其他缓冲区：`WebGLBuffer`, `WebGLRenderbuffer`


WebGLActiveInfo - Web API 接口参考

WebGLActiveInfo
===============

**WebGLActiveInfo**是WebGL API 的一部分，并且代表了调用 `WebGLRenderingContext.getActiveAttrib()` (en-US) 和`WebGLRenderingContext.getActiveUniform()` (en-US) 这两个方法后传回的信息。

属性值
---

`WebGLActiveInfo.name` (en-US)

请求变量的只读名称。

`WebGLActiveInfo.size` (en-US)

请求变量的只读尺寸。

`WebGLActiveInfo.type` (en-US)

请求变量的只读类型。

示例
--

`WebGLActiveInfo` 对象可以通过以下方式返回：

* `WebGLRenderingContext.getActiveAttrib()` (en-US)
* `WebGLRenderingContext.getActiveUniform()` (en-US)
* `WebGL2RenderingContext.getTransformFeedbackVarying()` (en-US)

```js
WebGLActiveInfo? getActiveAttrib(WebGLProgram? program, GLuint index);
WebGLActiveInfo? getActiveUniform(WebGLProgram? program, GLuint index);
WebGLActiveInfo? getTransformFeedbackVarying(WebGLProgram? program, GLuint index)
```

规范
--

| Specification |
| --- |
| WebGL Specification # 5.11 |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

另请参见
----

* `WebGLRenderingContext.getActiveAttrib()` (en-US)
* `WebGLRenderingContext.getActiveUniform()` (en-US)


Background Tasks API - Web API 接口参考

Background Tasks API
====================

**后台任务协作调度 API**（Cooperative Scheduling of Background Tasks API，也叫后台任务 API，或者简单称为 `requestIdleCallback()` API）提供了由用户代理决定的，在空闲时间自动执行队列任务的能力。

**备注：** 此 API *无法*在 Web Worker 中使用。

概念和用法
-----

浏览器的主线程以其事件循环队列为中心。此代码渲染 `Document` 上待更新展示的内容，执行页面待运行的 JavaScript 脚本，接收来自输入设备的事件，以及分发事件给需要接收事件的元素。此外，事件循环队列处理与操作系统的交互、浏览器自身用户界面的更新等等。这是一个非常繁忙的代码块，你的主要 JavaScript 代码可能会和这些代码一起也在这个线程中执行。当然，大多数（不是所有）能够更改 DOM 的代码都在主线程中运行，因为用户界面更改通常只对主线程可用。

因为事件处理和屏幕更新是用户关注性能最明显的两种方式。对于你的代码来说，防止在事件队列中出现卡顿是很重要的。在过去，除了编写尽可能高效的代码和将尽可能多的工作移交给 worker 之外，没有其他可靠的方法可以做到这一点。`Window.requestIdleCallback()` 允许浏览器告诉你的代码可以安全使用多少时间而不会导致系统延迟，从而有助于确保浏览器的事件循环平稳运行。如果你保持在给定的范围内，你可以使用户体验更好。

### 充分利用空闲回调

因为 idle callback 旨在为代码提供一种与事件循环协作的方式，以确保系统充分利用其潜能，不会过度分配任务，从而导致延迟或其他性能问题，因此你应该考虑如何使用它。

* **对非高优先级的任务使用空闲回调**。已经创建了多少回调，用户系统的繁忙程度，你的回调多久会执行一次（除非你指定了 `timeout`），这些都是未知的。不能保证每次事件循环（甚至每次屏幕更新）后都能执行空闲回调；如果事件循环用尽了所有可用时间，那你可就倒霉了（再说一遍，除非你用了 `timeout`）。
* **空闲回调应尽可能不超支分配到的时间**。尽管即使你超出了规定的时间上限，通常来说浏览器、代码、网页也能继续正常运行，这里的时间限制是用来保证系统能留有足够的时间去完成当前的事件循环然后进入下一个循环，而不会导致其他代码卡顿或动画效果延迟。目前，`timeRemaining()` 有一个 50 ms 的上限时间，但实际上你能用的时间比这个少，因为在复杂的页面中事件循环可能已经花费了其中的一部分，浏览器的扩展插件也需要处理时间，等等。
* **避免在空闲回调中改变 DOM**。空闲回调执行的时候，当前帧已经结束绘制了，所有布局的更新和计算也已经完成。如果你做的改变影响了布局，你可能会强制停止浏览器并重新计算，而从另一方面来看，这是不必要的。如果你的回调需要改变 DOM，它应该使用 `Window.requestAnimationFrame()` 来调度它。
* **避免运行时间无法预测的任务**。你的空闲回调必须避免做任何占用时间不可预测的事情。比如说，应该避免做任何会影响页面布局的事情。你也必须避免 执行`Promise` (en-US) 的 `resolve` 和 `reject`，因为这会在你的回调函数返回后立即引用 Promise 对象对 `resolve` 和 `reject` 的处理程序。
* **在你需要的时候要用 timeout，但记得只在需要的时候才用**。使用 timeout 可以保证你的代码按时执行，但是在剩余时间不足以强制执行你的代码的同时保证浏览器的性能表现的情况下，timeout 就会造成延迟或者动画不流畅。
### 回退到 setTimeout

因为后台任务 API 还是相当新的，而你的代码可能需要在那些不仍不支持此 API 的浏览器上运行。你可以把 `setTimeout()` (en-US) 用作回调选项来做这样的事。这个并不是 polyfill ，因为它在功能上并不相同；`setTimeout()` 并不会让你利用空闲时段，而是使你的代码在情况允许时执行你的代码，以使我们可以尽可能地避免造成用户体验性能表现延迟的后果。

```js
window.requestIdleCallback =
  window.requestIdleCallback ||
  function (handler) {
    let startTime = Date.now();

    return setTimeout(function () {
      handler({
        didTimeout: false,
        timeRemaining: function () {
          return Math.max(0, 50.0 - (Date.now() - startTime));
        },
      });
    }, 1);
  };
```

如果 `window.requestIdleCallback` 是 undefined, 我们在这里把它创建出来。这个函数首先会记录我们调用具体实现的时间。我们将用它计算填充程序 `timeRemaining()` 返回的值。

接着，我们调用 `setTimeout()` (en-US)，并给它传一个函数，在这个函数里，我们传给 `requestIdleCallback()` 的具体实现的回调会得以执行。这个回调会接收一个和 `IdleDeadline` 相符合的 object，此 object 的 `didTimeout` (en-US) 被设定为 false，并拥有一个 `timeRemaining()` 方法，用来给回调函数 50 毫秒的开始时间。每次调用 `timeRemaining()`，它都会从开始的 50 毫秒中减去已逝去的时间，来确定还剩余的时间。

结果是，虽然我们的填充程序不会像真正的 `requestIdleCallback()` 将自己限制在当前事件循环传递中的空闲时间内，但它至少将每次传递的运行时间限制为不超过 50 毫秒。

我们 `cancelIdleCallback()` 的具体实现要简单的多。

```js
window.cancelIdleCallback =
  window.cancelIdleCallback ||
  function (id) {
    clearTimeout(id);
  };
```

如果 `cancelIdleCallback()` 没有定义，它将创建一个来简单地把指定回调 ID 传递给 `clearTimeout()`。

现在，尽管效率不高，你的代码也可以在不支持后台任务 API 的浏览器上运行了。

接口
--

后台任务 API 只添加了一个新的接口：

`IdleDeadline`

这个类型的对象接口空闲回调以提供空闲时段的预估持续时长，以及回调是否因为定时时段过期使其正在运行当中。

这个 API 给 `Window` 接口增加了新的 `requestIdleCallback()` 和 `cancelIdleCallback()` 方法。

示例
--

在这个示例中，我们将了解我们怎么用 `requestIdleCallback()` 来在浏览器空闲时运行高耗时、低优先级的任务。此外，这个示例会演示如何使用 `requestAnimationFrame()` 安排文档内容的更新。

在下面，你只会看到示例的 HTML 和 JavaScript。CSS 没有展示出来，因为它对理解此功能并不关键。

### HTML

为了了解我们的目标，看一下 HTML。这里创建了一个盒子（`id="container"`）来显示操作进度（因为毕竟我们没法知道解码“量子丝极谱发射”会用多长时间），还创建了一个次要的盒子（`id="logBox"`）来展示文本输出。

```html
<p>使用 <code>requestIdleCallback()</code> 方法的后台任务协作调度演示。</p>

<div id="container">
  <div class="label">解码量子丝极谱发射中...</div>

  <progress id="progress" value="0"></progress>

  <div class="button" id="startButton">开始</div>

  <div class="label counter">
    任务 <span id="currentTaskNumber">0</span> /
    <span id="totalTaskCount">0</span>
  </div>
</div>

<div id="logBox">
  <div class="logHeader">记录</div>
  <div id="log"></div>
</div>
```

这个进度框用一个 `<progress>` 元素展示进度，随着它标签部分的变化，会呈现进度的数字信息。此外，这还有一个开始按钮（id 为“startButton”），用户可以使用它开始数据处理。
```

body {
  font-family: "Open Sans", "Lucida Grande", "Arial", sans-serif;
  font-size: 16px;
}

#logBox {
  margin-top: 16px;
  width: 400px;
  height: 500px;
  border-radius: 6px;
  border: 1px solid black;
  box-shadow: 4px 4px 2px black;
}

.logHeader {
  margin: 0;
  padding: 0 6px 4px;
  height: 22px;
  background-color: lightblue;
  border-bottom: 1px solid black;
  border-radius: 6px 6px 0 0;
}

#log {
  font:
    12px "Courier",
    monospace;
  padding: 6px;
  overflow: auto;
  overflow-y: scroll;
  width: 388px;
  height: 460px;
}

#container {
  width: 400px;
  padding: 6px;
  border-radius: 6px;
  border: 1px solid black;
  box-shadow: 4px 4px 2px black;
  display: block;
  overflow: auto;
}

.label {
  display: inline-block;
}

.counter {
  text-align: right;
  padding-top: 4px;
  float: right;
}

.button {
  padding-top: 2px;
  padding-bottom: 4px;
  width: 100px;
  display: inline-block;
  float: left;
  border: 1px solid black;
  cursor: pointer;
  text-align: center;
  margin-top: 0;
  color: white;
  background-color: darkgreen;
}

#progress {
  width: 100%;
  padding-top: 6px;
}
```

### JavaScript

现在，已经定义了文档结构，再构造出 JavaScript 代码就可以运行了。目标：可以向队列添加调用函数的请求，并具有一个空闲回调，空闲回调会在系统空闲且空闲时间足够长以取得进展时运行。

#### 变量声明

```js
const taskList = [];
let totalTaskCount = 0;
let currentTaskNumber = 0;
let taskHandle = null;
```

这些变量用于管理等待执行的任务列表和任务队列和其执行的状态信息：

* `taskList` 是一个对象的 `Array`，每个对象代表一个待运行的任务。
* `totalTaskCount` 是一个已被添加到队列的任务数量计数器，只会增大，不会减小。我们用它计算总工作量进度的百分比值。
* `currentTaskNumber` 用于追踪到现在为止已处理了多少任务。
* `taskHandle` 是对当前处理中任务的一个引用。

```js
const totalTaskCountElem = document.getElementById("totalTaskCount");
const currentTaskNumberElem = document.getElementById("currentTaskNumber");
const progressBarElem = document.getElementById("progress");
const startButtonElem = document.getElementById("startButton");
const logElem = document.getElementById("log");
```

接下来我们有了引用要交互 DOM 元素的变量。这些元素是：

* `totalTaskCountElem` `<span>` 用于插入我们在进度框显示状态中创建的任务总数。
* `currentTaskNumberElem` 是我们用来呈现到当前为止处理过的任务数的元素。
* `progressBarElem` `<progress>`，我们用它来呈现到当前为止处理过任务的百分比。
* `startButtonElem` 是开始按钮。
* `logElem` 我们在 `<div>` 中显示记录过的文本信息。

```js
let logFragment = null;
let statusRefreshScheduled = false;
```

最后，我们为其他项目设置一对变量：

* `logFragment` 当渲染下一帧，我们的记录方法都会生成一个 `DocumentFragment` 来创建添加到记录的内容，并保存到 `logFragment` 中 `DocumentFragment` 。
* `statusRefreshScheduled` 我们用它来追踪我们是否已经为即将到来的帧安排了状态显示框的更新，所以我们每一帧只执行一次。
```

requestIdleCallback =
  requestIdleCallback ||
  ((handler) => {
    const startTime = Date.now();

    return setTimeout(() => {
      handler({
        didTimeout: false,
        timeRemaining() {
          return Math.max(0, 50.0 - (Date.now() - startTime));
        },
      });
    }, 1);
  });

cancelIdleCallback =
  cancelIdleCallback ||
  ((id) => {
    clearTimeout(id);
  });
```

#### 管理任务队列

接下来，让我们来了解我们管理需要执行的任务的方式。为此，我们将创建一个先进先出（FIFO）的任务队列，在空闲回调期间，如果时间允许，我们将执行这个队列。

##### 排队任务

首先，我们需要一个函数把任务排成队列，以便将来执行。这个函数 `enqueueTask()`，就像这个：

```js
function enqueueTask(taskHandler, taskData) {
  taskList.push({
    handler: taskHandler,
    data: taskData,
  });

  totalTaskCount++;

  if (!taskHandle) {
    taskHandle = requestIdleCallback(runTaskQueue, { timeout: 1000 });
  }

  scheduleStatusRefresh();
}
```

`enqueueTask()` 接受两个参数作为参数

* `taskHandler` 一个函数，被调用来处理任务。
* `taskData` 一个对象（object），被当作输入参数传递给 `taskHandler`，以允许任务接收自定义数据。

为了把任务排成队列，我们把一个对象添加到 `taskList` 数组；此对象包含 `taskHandler` 和 `taskData` 的值（命名分别是 `handler` 和 `data`），然后体现我们队列里任务总数的 `totalTaskCount` 增加（我们不会在从队列中移除任务时减少 `totalTaskCount`）。

接下来，我们来检查我们是否已经创建了一个空闲回调；如果 `taskHandle` 是 0，那我们得知还没有空闲回调，所以我们调用 `requestIdleCallback()` 去创建一个。它被配置为调用一个叫 `runTaskQueue()` 的函数（我们随后会对其研究），它的 `timeout` 为 1 秒，因此，即使没有任何实际可用的空闲时间，它也至少会每秒运行一次。

##### 执行任务

我们的空闲回调处理方法，`runTaskQueue()`，将在浏览器确定有足够的可用空闲时间让我们做一些我们的工作时，或者 1 秒的 `timeout` 到期时被调用。这个方法的作用是执行队列中的任务。

```js
function runTaskQueue(deadline) {
  while (
    (deadline.timeRemaining() > 0 || deadline.didTimeout) &&
    taskList.length
  ) {
    const task = taskList.shift();
    currentTaskNumber++;

    task.handler(task.data);
    scheduleStatusRefresh();
  }

  if (taskList.length) {
    taskHandle = requestIdleCallback(runTaskQueue, { timeout: 1000 });
  } else {
    taskHandle = 0;
  }
}
```

`runTaskQueue()` 的核心是一个循环，只要有剩余时间（通过检查 `deadline.timeRemaining` 来确认它大于 0），或者已经达到了超时（timeout）期限（`deadline.didTimeout` (en-US) 值为真），且任务列表中有任务就会一直持续。

对队列中每个我们有时间执行的任务，我们做以下操作：

1. 我们把任务对象（object）从队列中移除。
2. 我们让 `currentTaskNumber` 增加来追踪我们已执行的任务数量。
3. 我们调用任务处理方法，`task.handler`，并任务的数据对象（`task.data`）传入其中。
4. 我们调用一个方法，`scheduleStatusRefresh()`，去处理调度一个屏幕更新来体现我们进度的变化。

当时间耗尽，如果列表里还有任务，我们再次调用 `requestIdleCallback()` 使我们可以在下次有可用空闲时间时继续运行这些任务。如果队列是空的，我们将把 `taskHandle` 设置为 0 来表示我们没有回调日程了。这样，下一次 `enqueueTask()` 被调用时，我们就知道要请求一个回调了。

#### 更新状态显示

我们想要能够做的一件事是根据记录输出和进度信息来更新文档。然后在空闲回调中改变 DOM 是不安全的。作为替代，我们使用 `requestAnimationFrame()` 来让浏览器在可以安全地更新显示时通知我们。

##### 安排显示的更新

调用 `scheduleStatusRefresh()` 函数来安排 DOM 的改变。

```js
function scheduleStatusRefresh() {
  if (!statusRefreshScheduled) {
    requestAnimationFrame(updateDisplay);
    statusRefreshScheduled = true;
  }
}
```

这是一个简单的函数。它检查 `statusRefreshScheduled` 的值来得知我们是否已经安排了一个显示更新。如果值为 `false`，我们调用 `requestAnimationFrame()` 来安排一个更新，也就是提供一个 `updateDisplay()` 函数以被调用去处理那个工作。

##### 更新显示

`updateDisplay()` 函数负责绘制进度框的内容和记录。当 DOM 的状况安全，我们可以在下次渲染过程中申请改变时，浏览器会调用它。

```js
function updateDisplay() {
  const scrolledToEnd =
    logElem.scrollHeight - logElem.clientHeight <= logElem.scrollTop + 1;

  if (totalTaskCount) {
    if (progressBarElem.max !== totalTaskCount) {
      totalTaskCountElem.textContent = totalTaskCount;
      progressBarElem.max = totalTaskCount;
    }

    if (progressBarElem.value !== currentTaskNumber) {
      currentTaskNumberElem.textContent = currentTaskNumber;
      progressBarElem.value = currentTaskNumber;
    }
  }

  if (logFragment) {
    logElem.appendChild(logFragment);
    logFragment = null;
  }

  if (scrolledToEnd) {
    logElem.scrollTop = logElem.scrollHeight - logElem.clientHeight;
  }

  statusRefreshScheduled = false;
}
```

首先，在记录被滚动到底的时候 `scrolledToEnd` 会被设置为 `true`，否则被设置为 `false`。我们用它来决定，我们是否必须要更新滚动位置来确保我们在给记录添加内容的动作结束后，记录停留在末尾。

接下来，如果有任务进入队列中，我们更新进度和状态信息。

1. 如果进度条当前的最大值不同于队列中当前的任务总数（`totalTaskCount`），我们就要更新任务总数（`totalTaskCountElem`）的显示内容和进度条的最大值，以使它的比例正确。
2. 我们对已运行的任务数做同样的操作；如果 `progressBarElem.value` 不同于当前正被处理的任务数（`currentTaskNumber`），我们就要更新当前运行的程序数量值和进度条当前值的显示。

然后，如果有文本等待被添加到记录中（也就是说，`logFragment` 不为 `null`），我们使用 `Element.appendChild()` 将它添加到记录元素中，并将 `logFragment` 设置为以避免重复操作。

如果我们操作开始的时候记录被滚动到末尾，我们要确保它一直处理末尾的位置。然后我们将 `statusRefreshScheduled` 设置为 `false`，以表明我们已经处理过更新，可以安全地请求新的更新了。

#### 向记录添加文本

`log()` 函数可以向记录中添加指定的文本。因为我们不知道调用 `log()` 的时候是否可以立即安全地联系 DOM，我们将缓存记录文本一直到可以安全更新。在上面，在 `updateDisplay()` 的代码中，你可以找到更新动画帧时，实际添加记录的代码。

```js
function log(text) {
  if (!logFragment) {
    logFragment = document.createDocumentFragment();
  }

  const el = document.createElement("div");
  el.textContent = text;
  logFragment.appendChild(el);
}
```

首先，如果当前不存在一个名为 `logFragment` 的 `DocumentFragment` 对象。该元素是伪 DOM，我们可以在其中插入元素，而无需立即更改主 DOM 本身。

然后我们创建一个新的元素，并将其内容设置为与输入文本匹配。接下来我们向 `logFragment` 中的伪 DOM 末尾添加一个新的元素。`logFragment` 将会累积记录条目直到下次因 DOM 改变而调用 `updateDisplay()` 的时候。

### 运行任务

现在，我们的任务管理和显示维护代码已经完成了，我们实际上可以开始设定完成工作的代码了

#### 任务处理器

`logTaskHandler()`，将是我们用来作为任务处理器的函数，也是用作任务对象 `handler` 属性的值。它是一个简单的为每个任务向记录输出大量内容的函数。在你自己的应用程序中，你可以将此代码替换为你希望在空闲时间执行的任何任务。只要记住任何 DOM 变化都需要通过 `requestAnimationFrame()` 处理。

```js
function logTaskHandler(data) {
  log(`运行任务 #${currentTaskNumber}`);

  for (let i = 0; i < data.count; i += 1) {
    log(`${(i + 1).toString()}. ${data.text}`);
  }
}
```

#### 主程序

当用户点击“开始”按钮，会触发所有操作，也会导致调用 `decodeTechnoStuff()` 函数。
```

function getRandomIntInclusive(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() \* (max - min + 1)) + min;
}
```

```js
function decodeTechnoStuff() {
  totalTaskCount = 0;
  currentTaskNumber = 0;
  updateDisplay();

  const n = getRandomIntInclusive(100, 200);

  for (let i = 0; i < n; i++) {
    const taskData = {
      count: getRandomIntInclusive(75, 150),
      text: `该文本来自任务 ${i + 1}/${n}`,
    };

    enqueueTask(logTaskHandler, taskData);
  }
}

document
  .getElementById("startButton")
  .addEventListener("click", decodeTechnoStuff, false);
```

`decodeTechnoStuff()` 开始执行时会将任务总数（到现在为止添加到队列中的任务数）清零，并随后调用 `updateDisplay()` 以重置显示为“没有任何事发生”的状态。

这个示例去创建一个随机数量（100 到 200 之间）的任务。为此，我们使用 `Math.random()` 文档中作为示例提供的 `getRandomIntInclusive()` 函数来获得要创建的任务数。

随后我们开始一个循环以创建实际的任务。对于每个任务，我们创建一个对象，`taskData`，其中包含两个属性：

* `count` 是要从任务输出到记录中的字符串数量。
* `text` 是要输出到日志的文本（由 `count` 指定的次数）。

我们调用 `enqueueTask()` 来将每个任务排入队列，将 `logTaskHandler()` 传入作为处理函数，将 `taskData` 传入，待处理函数调用时传入其中。

### 结果

下面就是以上代码实际功能结果。试一下，在你的浏览器开发者工具中使用它，并把它融入自己的代码中体验一下。

规范
--

| Specification |
| --- |
| requestIdleCallback() Cooperative Scheduling of Background Tasks # the-requestidlecallback-method |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `Window.requestIdleCallback()`
* `Window.cancelIdleCallback()`
* `IdleDeadline`


WakeLock - Web API 接口参考

WakeLock
========

**实验性:** **这是一项实验性技术**
在将其用于生产之前，请仔细检查浏览器兼容性表格。

**安全上下文:** 此项功能仅在一些支持的浏览器的安全上下文（HTTPS）中可用。

**`WakeLock`** 接口允许一个文件获取屏幕唤醒锁定。

方法
--

`WakeLock.request()`

返回一个决议为 `WakeLockSentinel` (en-US) 的 `Promise` 或当唤醒锁定不可访问的时候抛出异常。

示例
--

以下例子获取一个唤醒锁定并在 10 分钟后释放它：
```

function tryKeepScreenAlive(minutes) {
  navigator.wakeLock.request("screen").then(lock => {
    setTimeout(() => lock.release(), minutes * 60 * 1000);
  });
}

tryKeepScreenAlive(10);
```

规范
--

| Specification |
| --- |
| Screen Wake Lock API # the-wakelock-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

相关链接
----

* `Navigator.wakeLock` (en-US)


CustomEvent - Web API 接口参考

CustomEvent
===========

`CustomEvent` 接口表示由程序出于某个目的而创建的事件。

**备注：** 此特性在 Web Worker 中可用

Event

CustomEvent构造函数
----

`CustomEvent()`

创建一个新的 `CustomEvent`。

属性
--

*此接口从父接口 `Event` 继承属性。*

`CustomEvent.detail` 只读

返回在初始化事件时传入的任何数据。

方法
--

*此接口从父接口 `Event` 继承方法。*

`CustomEvent.initCustomEvent()`
已弃用

初始化一个 `CustomEvent` 对象。如果事件已经被触发，这个方法将不会起任何作用。

规范
--

| Specification |
| --- |
| DOM Standard # interface-customevent |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `Window.postMessage()`
* 创建和触发事件


PerformanceNavigation - Web API 接口参考

PerformanceNavigation
=====================

**`PerformanceNavigation`** 接口呈现了如何导航到当前文档的信息。

这个类型的对象可以被只读属性`Performance.navigation`调用。

Properties
----------

*`PerformanceNavigation` 接口不继承任何属性。*

`PerformanceNavigation.type` (en-US) 只读

一个无符号短整型，表示是如何导航到这个页面的。可能的值如下：

`TYPE_NAVIGATE` (0)

当前页面是通过点击链接，书签和表单提交，或者脚本操作，或者在 url 中直接输入地址，type 值为 0

`TYPE_RELOAD` (1)

点击刷新页面按钮或者通过`Location.reload()`方法显示的页面，type 值为 1

`TYPE_BACK_FORWARD` (2)

页面通过历史记录和前进后退访问时。type 值为 2

`TYPE_RESERVED` (255)

任何其他方式，type 值为 255

`PerformanceNavigation.redirectCount` (en-US) 只读

无符号短整型，表示在到达这个页面之前重定向了多少次。

Methods
-------

**`Performance` 接口没有继承任何方法**

`PerformanceNavigation.toJSON()` (en-US)
非标准

把`PerformanceNavigation`转换成 JSON 对象

规范
--

因为 Navigation Timing 规范已被弃用，此特性不再有望成为标准。请使用 `PerformanceNavigationTiming` 接口代替。

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* The `Performance` that allows access to an object of this type.
* `PerformanceNavigationTiming` (part of Navigation Timing Level 2)
实验性


Push API - Web API 接口参考

Push API
========

**Push API** 给与了 Web 应用程序接收从服务器发出的推送消息的能力，无论 Web 应用程序是否在用户设备前台，甚至刚加载完成。这样，开发人员就可以向用户投放异步通知和更新，从而让用户能更及时地获取新内容。

Push 的概念及用法
-----------

**警告：** 在实现 PushManager 订阅时，请确保你的应用程序免受 CSRF/XSRF（跨站请求伪造）问题。参见以下的文章以了解更多信息：

* 跨站请求伪造（CSRF）预防清单
* 防止 CSRF 和 XSRF 攻击

对于一个应用来说，要想要接收到推送消息，需要有一个激活的 service worker。当 service worker 处于激活状态时，可以使用 `PushManager.subscribe()` 来订阅推送通知。

返回的 `PushSubscription` (en-US) 包含了有关应用需要发送的推送消息的所有信息：端点及发送数据需要的加密密钥。

Service worker 会在必要的时候启动并接收传入的推送消息，将其传递给 `onpush` (en-US) 事件处理器。该方法允许应用程序在接收到推送消息时作出反应，例如显示一条通知（使用 `ServiceWorkerRegistration.showNotification()` (en-US)）。

每一个订阅对 service worker 来说都是唯一的。同时订阅的端点也是一个唯一的功能性 URL：端点的信息是给应用发送信息的全部必要条件。所以端点地址需要保密，否则其他应用也可以向你的应用推送消息。

激活一个 service worker 来提供推送消息会导致资源消耗的增加，尤其是电池。不同的浏览器对此有不同的方案——目前为止还没有标准的机制。Firefox 允许对发送给应用的推送消息做数量限制（配额），但生成通知的推送消息不受此限制。该限制会在站点每一次被访问之后刷新。相比之下，Chrome 选择不作限制。

接口
--

`PushEvent` (en-US)

表示发送到 `ServiceWorker` 全局全局作用域的推送操作。它包含了从应用程序发送到 `PushSubscription` (en-US) 的消息。

`PushManager`

提供一种从第三方服务器接收通知和用于推送通知的请求 URL 的方法。

`PushMessageData` (en-US)

提供对服务器发送的推送数据的访问，包括在接收数据时对数据进行操作的方法。

`PushSubscription` (en-US)

提供一个订阅的端点 URL，并允许取消推送服务的订阅。

`PushSubscriptionOptions` (en-US)

表示与推送订阅相关联的选项。

Service worker 附加的内容
--------------------

以下附加到 Service Worker API 的内容已在 Push API 规范中定义，以提供使用推送消息的入口点。它们用于监听和响应推送和订阅改变的事件。

`ServiceWorkerRegistration.pushManager` 只读

返回对 `PushManager` 接口的一个引用，该接口用于管理 push 订阅，包括：订阅、获取一个活跃的订阅、获取 push 权限的状态。这是使用接收推送消息能力的入口点。

`onpush` (en-US)

一个在 `push` (en-US) 事件被触发时（即收到服务器的推送消息时）的事件处理器。

`onpushsubscriptionchange` (en-US)

一个在 `pushsubscriptionchange` (en-US) 事件被触发时（例如，推送服务器设置了过期时间，因而造成推送订阅已经或即将失效）的事件处理器。

示例
--

Mozilla 的 ServiceWorker Cookbook 中包含了许多关于 Push 有用的示例。

规范
--

| Specification |
| --- |
| Push API # pushevent-interface |
| Push API # pushmessagedata-interface |

浏览器兼容性
------

### api.PushEvent

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.PushMessageData

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 通过 Mozilla 推送服务发送具有 VAPID 标识的 WebPush 通知
* 推送通知概述
* Service Worker API


Notification - Web API 接口参考

Notification
============

**备注：** 此特性在 Web Worker 中可用

**安全上下文:** 此项功能仅在一些支持的浏览器的安全上下文（HTTPS）中可用。

Notifications API 的接口 `Notification` 用于配置以向用户显示桌面通知。

这些通知的外观和功能因平台而异，但通常它们会提供一种异步向用户提供信息的方式。

EventTarget

Notification构造函数
----

`Notification()`

创建一个新的 `Notification` 实例对象。

静态属性
----

这些属性只能用于 `Notification` 对象自身。

`Notification.permission` 只读

一个字符串，表示当前显示通知的权限。可能的值是：

* `denied`——用户拒绝显示通知。
* `granted`——用户接受显示通知。
* `default`——用户选择是未知的，因此浏览器的行为类似于值是 denied。

`Notification.maxActions_static` 只读
实验性

设备和用户代理支持的最大的操作数量。

实例属性
----

这些属性仅用于 `Notification` 实例对象上。

`Notification.actions` 只读
实验性

在构造函数的 `options` 参数中指定的通知的操作数组。

`Notification.badge` 只读

当没有足够的空间去显示通知自身（例如 Android 通知栏）时，用于表示通知图像的 URL。在安卓设备上，徽章的分辨率应达到 4x（约 96 x 96 px），图片会被自动屏蔽。

`Notification.body` 只读

在构造函数的 `options` 参数中指定的通知的正文字符串。

`Notification.data` 只读

返回一个通知数据的结构化克隆。

`Notification.dir` 只读

在构造函数的 `options` 参数中指定的通知的文本方向。

`Notification.lang` 只读

在构造函数的 `options` 参数中指定的通知的语言。

`Notification.tag` 只读

在构造函数的 `options` 参数中指定的通知的 ID（如果有的话）。

`Notification.icon` 只读

在构造函数的 `options` 参数中用作指定通知图标的图像 URL。

`Notification.image` 只读
实验性

作为通知的一部分显示的图像 URL，在构造函数的选项参数中指定。

`Notification.renotify` 只读
实验性

指定在新通知取代旧通知后，是否应该通知用户。

`Notification.requireInteraction` 只读

一个布尔值，表示通知应该保持活动状态，直到用户点击或者关掉它，而不是自动关闭。

`Notification.silent` 只读

指定通知是否应该静音——即，无论设备的设置如何，都不应发出声音和振动。

`Notification.timestamp` 只读
实验性

指定通知创建或者应用时（过去、现在或者未来）的时间。

`Notification.title` 只读

在构造函数第一个参数中指定的通知标题。

`Notification.vibrate` 只读
实验性

为拥有振动硬件的终端设备指定振动模式。

静态方法
----

这些属性只能用于 `Notification` 对象自身。

`Notification.requestPermission()`

请求用户允许显示通知。

实例方法
----

这些属性仅用于 `Notification` 实例对象或者通过 `prototype` 提供。`Notification` 对象也继承自 `EventTarget` 接口。

`Notification.close()`

以编程方式关闭通知实例。

事件
--

`click`

当用户点击通知时触发。

`close`

当用户关闭通知时触发。

`error`

当通知发生错误时触发。

`show`

当通知显示时触发。

示例
--

假定有如下 HTML：

```html
<button onclick="notifyMe()">提醒我！</button>
```

可以按如下方式发送通知——在这里，我们提供了一个相当详细且完整的代码，如果你想要首先检查通知是否受支持，然后检查用户是否已授予当前源发送通知的权限，然后根据需要请求权限，最后发送一个通知。

```js
function notifyMe() {
  if (!("Notification" in window)) {
    // 检查浏览器是否支持通知
    alert("当前浏览器不支持桌面通知");
  } else if (Notification.permission === "granted") {
    // 检查是否已授予通知权限；如果是的话，创建一个通知
    const notification = new Notification("你好！");
    // …
  } else if (Notification.permission !== "denied") {
    // 我们需要征求用户的许可
    Notification.requestPermission().then((permission) => {
      // 如果用户接受，我们就创建一个通知
      if (permission === "granted") {
        const notification = new Notification("你好！");
        // …
      }
    });
  }

  // 最后，如果用户拒绝了通知，并且你想尊重用户的选择，则无需再打扰他们
}
```

在这里，我们不再展示一个在线实例，因为 Chrome 和 Firefox 不再允许从跨源的 `<iframe>` 请求通知权限，其他浏览器会陆续跟进。要查看实际示例，请查看我们的待办事项示例（参见在线运行的应用程序）。

**备注：** 在上面的示例中，我们生成了响应用户手势的的通知（点击按钮）。这不仅仅是最佳实践——你不应该向用户发送它们不同意的通知——而且未来浏览器将明确的禁止未响应用户手势发出的通知。例如，Firefox 已经从版本 72 开始就这么做了。

规范
--

| Specification |
| --- |
| Notifications API Standard # api |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 使用 Notifications API


EXT_float_blend - Web API 接口参考

EXT\_float\_blend
=================

WebGL API 的 `EXT_float_blend` 扩展允许使用 32 位浮点数组件来混合和绘制缓冲区。

若要查询该扩展是否存在，可以用方法：`WebGLRenderingContext.getExtension()`。更多信息可以参考 WebGL tutorial 中的 Using Extensions。

**备注：** 该扩展在 `WebGL1` 和`WebGL2` 上下文中均存在。但是，要使用它，你需要启用对 32 位浮点绘制缓冲区的使用`WEBGL_color_buffer_float` (en-US)（for WebGL1）或 `EXT_color_buffer_float` (en-US)（WebGL2）。通过启用 32 位浮点缓冲区扩展，将自动启用`EXT_float_blend`。

该组件启用后，使用 32 位浮点数混合方式绘制，调用 `drawArrays()` 或 `drawElements()` 时，将不再产生 `INVALID_OPERATION` 异常。

使用说明
----

在支持 `EXT_float_blend` 扩展的设备上，当以下几种有一种或几种扩展启用时`EXT_color_buffer_float` (en-US), `OES_texture_float` (en-US), 或 `WEBGL_color_buffer_float` (en-US)，该扩展将会自动、隐式的启用。这确保了在该扩展定义之前的内容也都能够按照预期正确执行。

例子
--

```js
const gl = canvas.getContext("webgl2");

// enable necessary extensions
gl.getExtension("EXT\_color\_buffer\_float");
gl.getExtension("EXT\_float\_blend");

const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE\_2D, tex);

// use floating point format
gl.texImage2D(gl.TEXTURE\_2D, 0, gl.RGBA32F, 1, 1, 0, gl.RGBA, gl.FLOAT, null);

const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(
  gl.FRAMEBUFFER,
  gl.COLOR\_ATTACHMENT0,
  gl.TEXTURE\_2D,
  tex,
  0,
);

// enable blending
gl.enable(gl.BLEND);

gl.drawArrays(gl.POINTS, 0, 1);
// won't throw gl.INVALID\_OPERATION with the extension enabled
```

规范
--

| Specification |
| --- |
| WebGL EXT\_float\_blend Extension Specification  |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

其他参考
----

* WebGL API
* Using WebGL extensions
* WebGL 教程
* `WebGLRenderingContext.getExtension()`
* `EXT_color_buffer_float` (en-US)
* `WEBGL_color_buffer_float` (en-US)
* `WebGLRenderingContext.drawArrays()`
* `WebGLRenderingContext.drawElements()`


VRPose - Web API 接口参考

VRPose
======

**实验性:** **这是一项实验性技术**
在将其用于生产之前，请仔细检查浏览器兼容性表格。

The **`VRPose`** interface of the WebVR API represents the state of a VR sensor at a given timestamp (which includes orientation, position, velocity, and acceleration information.)

WebVR API 中的 **`VRPose`** 接口表示在一个给定的时间戳中，一个 VR 传感器的状态（包括了方向、位置、速度和加速度信息）。

This interface is accessible through the `VRDisplay.getPose()` (en-US) and `VRDisplay.getImmediatePose()` (en-US) methods.

这个接口能通过 `VRDisplay.getPose()` (en-US) 和 `VRDisplay.getImmediatePose()` (en-US) 方法访问

Properties
----------

`VRPose.timeStamp` 只读

返回当前系统的时间戳。此单调递增的值可以有助于确定位置数据是否有更新，以及更新的顺序。

`VRPose.position` (en-US) 只读

以三维向量的形式返回当前时间戳 `VRPose.timestamp` 时 `VRDisplay` 的位置信息。

`VRPose.linearVelocity` (en-US) 只读

返回当前时间戳 `VRPose.timestamp` 时 `VRDisplay` 的线速度，单位为米/秒。

`VRPose.linearAcceleration` (en-US) 只读

返回当前时间戳 `VRPose.timestamp` 时 `VRDisplay` 的线加速度，单位为米/平方秒。

`VRPose.orientation` (en-US) 只读

以四元数的形式返回当前时间戳 `VRPose.timestamp` 时传感器的方向，

`VRPose.angularVelocity` (en-US) 只读

返回当前时间戳 `VRPose.timestamp` 时 `VRDisplay` 的角速度，单位为弧度/秒。

`VRPose.angularAcceleration` (en-US) 只读

返回当前时间戳 `VRPose.timestamp` 时 `VRDisplay` 的角加速度，单位为弧度/平方秒。

Examples
--------
```

TBD.
```

Specifications
--------------

该 API 在旧的 WebVR API（已被 WebXR Device API 取代）中定义。它不再有望成为标准。

在所有浏览器都实现新的 WebXR API (en-US) 之前，建议使用框架（如：A-Frame、Babylon.js 或 Three.js）或 polyfill 来开发适用于所有浏览器的 WebXR 应用程序。[1]

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* WebVR API


TouchEvent - Web API 接口参考

TouchEvent
==========

`TouchEvent` 是一类描述手指在触摸平面（触摸屏、触摸板等）的状态变化的事件。这类事件用于描述一个或多个触点，使开发者可以检测触点的移动，触点的增加和减少，等等。

每 个 `Touch` 对象代表一个触点; 每个触点都由其位置，大小，形状，压力大小，和目标 `element` 描述。 `TouchList` 对象代表多个触点的一个列表。

构造函数
----

`TouchEvent()` (en-US)

创建一个`TouchEvent`对象。

属性列表
----

*`TouchEvent`的属性继承了 `UIEvent` 和 `Event`。*

`TouchEvent.altKey` 只读

布尔值，指明触摸事件触发时，键盘 alt 键是否被按下。

`TouchEvent.changedTouches` 只读

一个 `TouchList` 对象，包含了代表所有从上一次触摸事件到此次事件过程中，状态发生了改变的触点的 `Touch` 对象。

`TouchEvent.ctrlKey` 只读

布尔值，指明触摸事件触发时，键盘 ctrl 键是否被按下。

`TouchEvent.metaKey` 只读

布尔值，指明触摸事件触发时，键盘 meta 键（Wikipedia - meta Key）是否被按下。

`TouchEvent.shiftKey` 只读

布尔值，指明触摸事件触发时，键盘 shift 键是否被按下。

`TouchEvent.targetTouches` 只读

一个 `TouchList` 对象，是包含了如下触点的 `Touch` 对象：触摸起始于当前事件的目标 `element` 上，并且仍然没有离开触摸平面的触点。

`TouchEvent.touches` 只读

一 个 `TouchList` 对象，包含了所有当前接触触摸平面的触点的 `Touch` 对象，无论它们的起始于哪个 `element` 上，也无论它们状态是否发生了变化。

触摸事件的类型
-------

为了区别触摸相关的状态改变，存在多种类型的触摸事件。可以通过检查触摸事件的 `TouchEvent.type` 属性来确定当前事件属于哪种类型

**备注：** 在很多情况下，触摸事件和鼠标事件会同时被触发（目的是让没有对触摸设备优化的代码仍然可以在触摸设备上正常工作）。如果你使用了触摸事件，可以调用 `event.preventDefault()` 来阻止鼠标事件被触发。

### `touchstart`

当用户在触摸平面上放置了一个触点时触发。事件的目标 `element` 将是触点位置上的那个目标 `element`

### `touchend`

当一个触点被用户从触摸平面上移除（即用户的一个手指或手写笔离开触摸平面）时触发。当触点移出触摸平面的边界时也将触发。例如用户将手指划出屏幕边缘。

事件的目标 `element` 与触发 `touchstart` 事件的目标 `element` 相同，即使 `touchend` 事件触发时，触点已经移出了该 `element` 。

已经被从触摸平面上移除的触点，可以在 `changedTouches` 属性定义的 `TouchList` 中找到。

### `touchmove`

当用户在触摸平面上移动触点时触发。事件的目标 `element` 和触发 `touchstart` 事件的目标 `element` 相同，即使当 `touchmove` 事件触发时，触点已经移出了该 `element` 。

当触点的半径、旋转角度以及压力大小发生变化时，也将触发此事件。

**备注：** 不同浏览器上 `touchmove` 事件的触发频率并不相同。这个触发频率还和硬件设备的性能有关。因此决不能让程序的运作依赖于某个特定的触发频率。

### `touchcancel`

当触点由于某些原因被中断时触发。有几种可能的原因如下（具体的原因根据不同的设备和浏览器有所不同）：

* 由于某个事件出现而取消了触摸：例如触摸过程被弹窗打断。
* 触点离开了文档窗口，而进入了浏览器的界面元素、插件或者其他外部内容区域。
* 当用户产生的触点个数超过了设备支持的个数，从而导致 `TouchList` 中最早的 `Touch` 对象被取消。
### 与 addEventListener() 和 preventDefault() 一起使用

很值得注意的是，在很多情况下，触摸事件和鼠标事件会一起触发（以使非触摸专用的代码仍然可以与用户交互）。如果你要使用触摸事件，你可以使用 `preventDefault()` 来取消鼠标事件。

但 Chrome 是例外，从版本 56（桌面版、安卓版和安卓 webview）开始，Chrome 中 `touchstart` and `touchmove` 的默认值就是 `true`，没有必要调用 `preventDefault()`。如果要重写这个行为，简单地将 `passive` 设置成 `false` 就行。这样设置可以阻止监听器在用户滚动时停止页面渲染。Google Developer 有一个简单的演示。

全局事件处理
------

**实验性:** **这是一项实验性技术**
在将其用于生产之前，请仔细检查浏览器兼容性表格。

`GlobalEventHandlers.ontouchstart`
实验性

使用一个 `global event handler` 处理`touchstart` 事件。

`GlobalEventHandlers.ontouchend` (en-US)
实验性

使用一个 `global event handler` 处理 `touchend` 事件。

`GlobalEventHandlers.ontouchmove`
实验性

使用一个 `global event handler` 处理 `touchmove` 事件。

`GlobalEventHandlers.ontouchcancel`
实验性

使用一个 `global event handler` 处理 `touchcancel` 事件。

实例
--

请看 example on the main Touch events article.

规范
--

| Specification |
| --- |
| Touch Events # touchevent-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

相关链接
----

* `Touch Events Overview`
* `GestureEvent`
* `MSGestureEvent`


DeviceOrientationEvent - Web API 接口参考

DeviceOrientationEvent
======================

**实验性:** **这是一项实验性技术**
在将其用于生产之前，请仔细检查浏览器兼容性表格。

`DeviceOrientationEvent` 提供给网页开发者当设备（指手机，平板等移动设备）在浏览页面时物理旋转的信息。

**警告：** 当前，火狐浏览器和谷歌浏览器并未能用同一种方式实现，在使用请注意。（见后文）

属性
--

`DeviceOrientationEvent.absolute` 只读

用来说明设备是提供的旋转数据是否是绝对定位的布尔值。

`DeviceOrientationEvent.alpha` 只读

一个表示设备绕 z 轴旋转的角度（范围在 0-360 之间）的数字

`DeviceOrientationEvent.beta` 只读

一个表示设备绕 x 轴旋转（范围在－180 到 180 之间）的数字，从前到后的方向为正方向。

`DeviceOrientationEvent.gamma` 只读

一个表示设备绕 y 轴旋转（范围在－90 到 90 之间）的数字，从左向右为正方向。

例子
--

```js
window.addEventListener("deviceorientation", function (event) {
  console.log(event.alpha + " : " + event.beta + " : " + event.gamma);
});
```

规范
--

| Specification |
| --- |
| DeviceOrientation Event Specification # deviceorientation |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `deviceorientation`
* `DeviceMotionEvent`
* `devicemotion`
* 监测设备方向 (en-US)
* 转动与运动的数据说明


FileReader - Web API 接口参考

FileReader
==========

**`FileReader`** 对象允许 Web 应用程序异步读取存储在用户计算机上的文件（或原始数据缓冲区）的内容，使用 `File` 或 `Blob` 对象指定要读取的文件或数据。

其中 File 对象可以是来自用户在一个`<input>`元素上选择文件后返回的`FileList`对象，也可以来自拖放操作生成的 `DataTransfer`对象，还可以是来自在一个`HTMLCanvasElement`上执行`mozGetAsFile()`方法后返回结果。

重要提示：FileReader 仅用于以安全的方式从用户（远程）系统读取文件内容 它不能用于从文件系统中按路径名简单地读取文件。要在 JavaScript 中按路径名读取文件，应使用标准 Ajax 解决方案进行服务器端文件读取，如果读取跨域，则使用 CORS 权限。

**备注：** 此特性在 Web Worker 中可用

构造函数
----

`FileReader()`

返回一个新构造的`FileReader`。

有关详细信息和示例，请参阅如何在 web 应用程序中使用文件。

属性
--

`FileReader.error` 只读

一个`DOMException`，表示在读取文件时发生的错误。

`FileReader.readyState` 只读

表示`FileReader`状态的数字。取值如下：

| 常量名 | 值 | 描述 |
| --- | --- | --- |
| `EMPTY` | `0` | 还没有加载任何数据。 |
| `LOADING` | `1` | 数据正在被加载。 |
| `DONE` | `2` | 已完成全部的读取请求。 |

`FileReader.result` 只读

文件的内容。该属性仅在读取操作完成后才有效，数据的格式取决于使用哪个方法来启动读取操作。

### 事件处理

`FileReader.onabort`

处理`abort`事件。该事件在读取操作被中断时触发。

`FileReader.onerror` (en-US)

处理`error`事件。该事件在读取操作发生错误时触发。

`FileReader.onload`

处理`load`事件。该事件在读取操作完成时触发。

`FileReader.onloadstart`

处理`loadstart`事件。该事件在读取操作开始时触发。

`FileReader.onloadend`

处理`loadend`事件。该事件在读取操作结束时（要么成功，要么失败）触发。

`FileReader.onprogress`

处理`progress`事件。该事件在读取`Blob`时触发。

**备注：** 因为 `FileReader` 继承自`EventTarget`，所以所有这些事件也可以通过`addEventListener`方法使用。

方法
--

`FileReader.abort()`

中止读取操作。在返回时，`readyState`属性为`DONE`。

`FileReader.readAsArrayBuffer()`

开始读取指定的 `Blob`中的内容，一旦完成，result 属性中保存的将是被读取文件的 `ArrayBuffer` 数据对象。

`FileReader.readAsBinaryString()`
非标准

开始读取指定的`Blob`中的内容。一旦完成，`result`属性中将包含所读取文件的原始二进制数据。

`FileReader.readAsDataURL()`

开始读取指定的`Blob`中的内容。一旦完成，`result`属性中将包含一个`data:` URL 格式的 Base64 字符串以表示所读取文件的内容。

`FileReader.readAsText()`

开始读取指定的`Blob`中的内容。一旦完成，`result`属性中将包含一个字符串以表示所读取的文件内容。

规范
--

| Specification |
| --- |
| File API # APIASynch |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 如何在 web 应用程序中使用文件
* `File`
* `Blob`
* `FileReaderSync`


网络信息 API - Web API 接口参考

网络信息 API
========

**实验性:** **这是一项实验性技术**
在将其用于生产之前，请仔细检查浏览器兼容性表格。

网络信息 API（Network Information API）提供关于系统连接的一般连接类型的信息（如“wifi”、“cellular”等）。应用程序可以根据此信息为用户展现不同清晰度的内容。

该接口由一个 `NetworkInformation` 对象组成，其实例由 `Navigator.connection` 属性返回。

**备注：** 此特性在 Web Worker 中可用

接口
--

`NetworkInformation`

提供设备用来与网络通信的连接信息，并在连接类型发生变化时为脚本提供通知的方式。`NetworkInformation` 接口不能被实例化。它可以通过 `Navigator` 接口访问。

示例
--

### 侦测连接状态变化

下面是一个侦测用户设备连接状态变化的例子。

```js
let type = navigator.connection.effectiveType;

function updateConnectionStatus() {
  console.log(
    `设备的网络连接从 ${type} 变为了 ${navigator.connection.effectiveType}`,
  );
  type = navigator.connection.effectiveType;
}

connection.addEventListener("change", updateConnectionStatus);
```

### 预加载大型资源

连接对象对于决定是否预装占用大量带宽或内存的资源很有用。这个示例将在页面加载后不久被调用，以检查预加载视频可能不可取的连接类型。如果发现有蜂窝网络连接，那么 `preloadVideo` 标志被设置为 `false`。为了简单明了，这个例子只测试了一种连接类型。真实世界的用例可能会使用 switch 语句或其他方法来检查 `NetworkInformation.type` (en-US) 的所有可能值。无论 `type` 值如何，你都可以通过 `NetworkInformation.effectiveType` (en-US) 属性获得对连接速度的估计。

```js
let preloadVideo = true;
const connection = navigator.connection;
if (connection) {
  if (connection.effectiveType === "slow-2g") {
    preloadVideo = false;
  }
}
```

规范
--

| Specification |
| --- |
| Network Information API # networkinformation-interface |
| Network Information API # connection-attribute |

浏览器兼容性
------

### api.NetworkInformation

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.Navigator.connection

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 在线（online）和离线（offline）事件 (en-US)


Performance API - Web API 接口参考

Performance API
===============

Performance API 是一组用于衡量 web 应用性能的标准。

概念和用法
-----

衡量和分析各种性能指标对于确保 web 应用的速度非常重要。Performance API 提供了重要的内置指标，并能够将你自己的测量结果添加到浏览器的性能时间线（performance timeline）中。性能时间线使用高精度的时间戳，且可以在开发者工具中显示。你还可以将相关数据发送到用于分析的端点，以根据时间记录性能指标。

每一个性能指标都使用一个性能条目（`PerformanceEntry`）表示。性能条目有名称（`name`）、持续时间（`duration`）、开始时间（`startTime`）和类型（`type`）。每一个性能指标都继承了 `PerformanceEntry` 接口，并对其进行限定。

大部分性能条目都在不需要任何额外操作的情况下进行记录，并可以通过 `Performance.getEntries()` 或（最好）通过 `PerformanceObserver` 访问。例如，`PerformanceEventTiming` (en-US) 条目用于记录花费的时间超过设定阈值的事件。而 Performance API 也允许你使用 `PerformanceMark` (en-US) 和 `PerformanceMeasure` (en-US) 接口定义和记录自定义事件。

`Performance` 主接口在全局作用域下可通过 `self.performance` 访问，并允许你增加自定义性能条目、清除性能条目，以及查询性能条目。

`PerformanceObserver` 接口允许你监听记录的不同类型的性能条目。

![Performance API 的 UML 图](/zh-CN/docs/Web/API/Performance_API/diagram.svg)

接口
--

`EventCounts` (en-US)

由 `performance.eventCounts` (en-US) 返回的只读映射，其中包含每个事件类型被分派的事件数量。

`LargestContentfulPaint` (en-US)

测量视口范围内可见的图像和文本块的最大渲染时间，从页面开始加载时开始记录。

`Performance`

用于性能测量的主接口。可在 window 和 worker 上下文中通过 `self.performance` 来访问。

`PerformanceElementTiming` (en-US)

测量特定元素的渲染时间戳。

`PerformanceEntry`

封装了单个性能指标的性能时间线条目。所有性能指标都继承自该接口。

`PerformanceEventTiming` (en-US)

测量事件的延迟和首次输入延迟（FID）。

`PerformanceLongTaskTiming`

检测占用渲染并阻止其他任务执行的长任务。

`PerformanceMark` (en-US)

在性能时间线上标记自定义条目。

`PerformanceMeasure` (en-US)

自定义使用两个性能条目表示的时间测量。

`PerformanceNavigationTiming`

测量文档导航事件，例如加载文档所需的时间。

`PerformanceObserver`

监听记录到性能时间线中的新的性能条目。

`PerformanceObserverEntryList` (en-US)

性能观察器（PerformanceObserver）中监测的条目的列表。

`PerformancePaintTiming`

测量网页构建期间的渲染操作。

`PerformanceResourceTiming`

测量网络负载指标，例如重定向开始和结束时间、（fetch）请求开始、DNS 查询开始和结束时间，以及图像、脚本、fetch 调用，等资源的响应开始和结束时间。

`PerformanceServerTiming` (en-US)

表示服务器的相关指标，在响应请求时与 `Server-Timing` HTTP 标头一起发送。

`TaskAttributionTiming` (en-US)

标识任务类型，及用于长任务测量的容器。

教程和指南
-----

* 使用 Performance API
* User Timing（概览）
* Navigation Timing（概览）
* Resource Timing（概览）
规范
--

| Specification |
| --- |
| Element Timing API  |
| Event Timing API  |
| High Resolution Time  |
| Largest Contentful Paint  |
| Layout Instability  |
| Long Tasks API  |
| Navigation Timing Level 2  |
| Paint Timing  |
| Performance Timeline  |
| Resource Timing  |
| Server Timing  |
| User Timing  |

参见
--

* Web 性能
* 学习：Web 性能


WebGLShader - Web API 接口参考

WebGLShader
===========

WebGL API 的 **WebGLShader** 可以是一个顶点着色器（vertex shader）或片元着色器（fragment shader）。每个 `WebGLProgram` 都需要这两种类型的着色器。

描述
--

要创建一个 **WebGLShader** 需要使用 `WebGLRenderingContext.createShader`，通过 `WebGLRenderingContext.shaderSource()` 然后挂接 GLSL 源代码 , 最后调用 `WebGLRenderingContext.compileShader()` 完成着色器（shader）的编译。此时 **WebGLShader** 仍不是可用的形式，他需要被添加到一个 `WebGLProgram`里。

```js
function createShader(gl, sourceCode, type) {
  // Compiles either a shader of type gl.VERTEX\_SHADER or gl.FRAGMENT\_SHADER
  var shader = gl.createShader(type);
  gl.shaderSource(shader, sourceCode);
  gl.compileShader(shader);

  if (!gl.getShaderParameter(shader, gl.COMPILE\_STATUS)) {
    var info = gl.getShaderInfoLog(shader);
    throw "Could not compile WebGL program. \n\n" + info;
  }
  return shader;
}
```

参看 `WebGLProgram` 关于添加着色器的信息。

范例
--

### 创建一个顶点着色器（vertex shader）

注意，有很多其他方式编译和访问着色器（shader）源代码字符串。这些示例仅用于例证说明。

```js
var vertexShaderSource =
  "attribute vec4 position;\n" +
  "void main() {\n" +
  " gl\_Position = position;\n" +
  "}\n";

//从上面例子使用 createShader 函数。
var vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX\_SHADER);
```

### 创建一个片元着色器（fragment shader）

```js
var fragmentShaderSource =
  "void main() {\n" + " gl\_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" + "}\n";

//从上面例子使用 createShader 函数。
var fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT\_SHADER);
```

规范
--

| Specification |
| --- |
| WebGL Specification # 5.8 |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参阅
--

* `WebGLProgram`
* `WebGLRenderingContext.attachShader()`
* `WebGLRenderingContext.bindAttribLocation()`
* `WebGLRenderingContext.compileShader()`
* `WebGLRenderingContext.createProgram()`
* `WebGLRenderingContext.createShader()`
* `WebGLRenderingContext.deleteProgram()`
* `WebGLRenderingContext.deleteShader()`
* `WebGLRenderingContext.detachShader()`
* `WebGLRenderingContext.getAttachedShaders()` (en-US)
* `WebGLRenderingContext.getProgramParameter()` (en-US)
* `WebGLRenderingContext.getProgramInfoLog()`
* `WebGLRenderingContext.getShaderParameter()`
* `WebGLRenderingContext.getShaderPrecisionFormat()` (en-US)
* `WebGLRenderingContext.getShaderInfoLog()` (en-US)
* `WebGLRenderingContext.getShaderSource()`
* `WebGLRenderingContext.isProgram()`
* `WebGLRenderingContext.isShader()`
* `WebGLRenderingContext.linkProgram()`
* `WebGLRenderingContext.shaderSource()`
* `WebGLRenderingContext.useProgram()`
* `WebGLRenderingContext.validateProgram()`


Web Component - Web API 接口参考

Web Component
=============

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Learn more
* See full compatibility
* Report feedback
Web Component 是一套不同的技术，允许你创建可重用的定制元素（它们的功能封装在你的代码之外）并且在你的 web 应用中使用它们。

概念和使用
-----

作为开发者，我们都知道尽可能多的重用代码是一个好主意。这对于自定义标记结构来说通常不是那么容易 — 想想复杂的 HTML（以及相关的样式和脚本），有时你不得不写代码来呈现自定义 UI 控件，并且如果你不小心的话，多次使用它们会使你的页面变得一团糟。

Web Components 旨在解决这些问题 — 它由三项主要技术组成，它们可以一起使用来创建封装功能的定制元素，可以在你喜欢的任何地方重用，不必担心代码冲突。

* **Custom element（自定义元素）**：一组 JavaScript API，允许你定义 custom elements 及其行为，然后可以在你的用户界面中按照需要使用它们。
* **Shadow DOM（影子 DOM）**：一组 JavaScript API，用于将封装的“影子”DOM 树附加到元素（与主文档 DOM 分开呈现）并控制其关联的功能。通过这种方式，你可以保持元素的功能私有，这样它们就可以被脚本化和样式化，而不用担心与文档的其他部分发生冲突。
* **HTML template（HTML 模板）：** `<template>` 和 `<slot>` 元素使你可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

实现 web component 的基本方法通常如下所示：

1. 创建一个类或函数来指定 web 组件的功能，如果使用类，请使用 ECMAScript 2015 的类语法 (参阅类获取更多信息)。
2. 使用 `CustomElementRegistry.define()` 方法注册你的新自定义元素，并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。
3. 如果需要的话，使用 `Element.attachShadow()` 方法将一个 shadow DOM 附加到自定义元素上。使用通常的 DOM 方法向 shadow DOM 中添加子元素、事件监听器等等。
4. 如果需要的话，使用 `<template>` 和 `<slot>` 定义一个 HTML 模板。再次使用常规 DOM 方法克隆模板并将其附加到你的 shadow DOM 中。
5. 在页面任何你喜欢的位置使用自定义元素，就像使用常规 HTML 元素那样。
教程
--

使用自定义元素

介绍如何使用自定义元素的功能来创建简单的 web component，以及生命周期回调和其他更高级的功能。

使用 shadow DOM

介绍 shadow DOM 的基础知识，展示如何向元素中附加 shadow DOM，添加到 shadow DOM 树，添加样式等等。

使用 template 和 slot

介绍如何使用 `<template>` 和 `<slot>` 元素定义可重用的 HTML 结构，然后在 Web component 中使用该结构。

参考
--

### 自定义元素

`CustomElementRegistry`

包含自定义元素相关功能，最值得注意的是 `CustomElementRegistry.define()` 方法用来注册新的自定义元素，这样就可以在文档中使用它们。

`Window.customElements`

返回 `CustomElementRegistry` 对象的引用。

生命周期回调

定义在自定义元素的类定义中的特殊回调函数，影响其行为：

* `connectedCallback`：当自定义元素第一次被连接到文档 DOM 时被调用。
* `disconnectedCallback`：当自定义元素与文档 DOM 断开连接时被调用。
* `adoptedCallback`：当自定义元素被移动到新文档时被调用。
* `attributeChangedCallback`：当自定义元素的一个属性被增加、移除或更改时被调用。

创建自定义内置元素的扩展

定义了以下扩展：

* `is` 全局 HTML 属性：允许你指定标准 HTML 元素像定义的内置元素一样工作。
* `Document.createElement()` 方法的“is”选项：允许你创建一个标准 HTML 元素的实例，表现得像一个给定的已注册的自定义内置元素。

CSS 伪类

与自定义元素特别相关的伪类：

* `:defined`：匹配任何已定义的元素，包括内置元素和使用 `CustomElementRegistry.define()` 定义的自定义元素。
* `:host`：选择 shadow DOM 的 shadow host，内容是它内部使用的 CSS（containing the CSS it is used inside）。
* `:host()`：选择 shadow DOM 的 shadow host，内容是它内部使用的 CSS（这样你可以从 shadow DOM 内部选择自定义元素）— 但只匹配给定方法的选择器的 shadow host 元素。
* `:host-context()`：选择 shadow DOM 的 shadow host，内容是它内部使用的 CSS（这样你可以从 shadow DOM 内部选择自定义元素）— 但只匹配给定方法的选择器匹配元素的子 shadow host 元素。

### Shadow DOM

`ShadowRoot`

表示 shadow DOM 子树的根节点。

`Element` extensions

与 shadow DOM 有关的 `Element` 接口的扩展：

* `Element.attachShadow()` 方法将 shadow DOM 树附加给特定元素。
* `Element.shadowRoot` 属性返回附加给特定元素的 shadow root，或者 `null` 如果没有 shadow root 被附加。

`Node` 相关拓展

与 shadow DOM 相关的 `Node` 接口的拓展：

* `Node.getRootNode()` 方法返回上下文对象的根，可以选择包含 shadow root，如果可用的话。
* `Node.isConnected` 属性返回一个布尔值表示节点是否连接（直接或间接）到上下文对象。例如，在普通 DOM 的情况下为 `Document` 对象，或者在 shadow DOM 的情况下为 `ShadowRoot` 。

`Event` 拓展

与 shadow DOM 相关的 `Event` 接口的扩展：

* `Event.composed`：返回 `Boolean` 它表明事件是否会通过 shadow DOM 边界传播到标准 DOM。
* `Event.composedPath`：返回事件的路径（侦听器将被调用的对象）。如果 shadow root 是使用 `ShadowRoot.mode` 为 closed 创建的，则不包括 shadow 树中的节点。

### HTML template

`<template>`

包含一个 HTML 片段，不会在文档初始化时渲染。但是可以在运行时使用 JavaScript 显示。主要用作自定义元素结构的基础。关联的 DOM 接口是`HTMLTemplateElement`。

`<slot>`

web component 中的一个占位符，你可以填充自己的标记，这样你就可以创建单独的 DOM 树并将它们呈现在一起。关联的 DOM 接口是`HTMLSlotElement`。

`slot` 全局 HTML 属性

将在 shadow DOM 树中的插槽分配给一个元素。

`Element.assignedSlot` (en-US)

一个只读属性，它返回对插入此元素的 `<slot>` 的引用。

`Text.assignedSlot`

一个只读属性，它返回对插入此文本节点的 `<slot>` 的引用。

`Element` 扩展

与插槽相关的 `Element` 接口的扩展：

* `Element.slot`：返回附加到元素上的 shadow DOM 插槽的名字。

CSS 伪元素

slots 特别相关的伪元素：

* `::slotted`：匹配任何已经插入一个 slot 的内容。

`slotchange` (en-US) 事件

当插槽中的节点改变时在 `HTMLSlotElement` 实例（`<slot>` 元素）上触发。

示例
--

在 web-components-examples，我们正在构建一些例子。以后会添加更多。

规范
--

| Specification |
| --- |
| HTML Standard # the-template-element |
| DOM Standard # interface-shadowroot |

浏览器兼容性
------

### html.elements.template

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.ShadowRoot

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* Open Web Components — Guides, tools and libraries for developing web components.
* DataFormsJS — Open source web components library — Set of Web Components that can be used to build Single Page Apps (SPA), Display JSON data from API's and Web Services, and bind data to different elements on screen. All Web Components are plain JavaScript and require no build process.
* FAST is a web component library built by Microsoft which offers several packages to leverage depending on your project needs. Fast Element is a lightweight means to easily build performant, memory-efficient, standards-compliant Web Components. Fast Foundation is a library of Web Component classes, templates, and other utilities built on fast-element intended to be composed into registered Web Components.
* Hybrids — Open source web components library, which favors plain objects and pure functions over `class` and `this` syntax. It provides a simple and functional API for creating custom elements.
* Lit — Google's web components library, the core of which is a component base class designed to reduce boilerplate while providing reactive state, scoped styles, and a declarative template system.
* Snuggsi — Easy Web Components in ~1kB *Including polyfill* — All you need is a browser and basic understanding of HTML, CSS, and JavaScript classes to be productive.
* Slim.js — Open source web components library — a high-performant library for rapid and easy component authoring; extensible and pluggable and cross-framework compatible.
* Stencil — Toolchain for building reusable, scalable design systems in web components.
* omi - Front End Cross-Frameworks Framework


触摸事件 - Web API 接口参考

触摸事件
====

为了给基于触摸的用户界面提供高质量的支持，触摸事件提供了在触摸屏或触控板上解释手指（或触控笔）活动的能力。

触摸事件接口是较为底层的 API，可为特定程序提供多点触控交互（比如双指手势）的支持。多点触控交互开始于一个手指（或触控笔）开始接触设备平面的时刻。随后其他手指也可触摸设备表面，并随意进行划动。当所有手指离开设备平面时，交互结束。整个交互期间，程序接收开始、移动、结束三个阶段的触摸事件。

触摸事件与鼠标事件类似，不同的是触摸事件还提供同一表面不同位置的同步触摸。`TouchEvent` 接口将当前所有活动的触摸点封装起来。`Touch` 接口表示单独一个触摸点，其中包含参考浏览器视角的相对坐标。

定义
--

表面（surface）

可感知触摸的平面，可以是屏幕或触控板。

触摸点（touch point）

表面上的一个接触点.。有可能是手指 (或者胳膊肘、耳朵、鼻子都行。但一般是手指) 或者触摸笔。

接口
--

`TouchEvent`

表示位于表面上的一个触摸点的某个状态发生改变时产生的事件。

`Touch`

表示用户与触摸表面间的一个单独的接触点。

`TouchList`

表示一组 Touch，用于多点触控的情况。

示例
--

本示例通过对多个触控点进行同步跟踪，让用户通过多点触控的方式在 `<canvas>` 元素上用两个（或以上）手指同时画图。本示例只在支持触摸事件的浏览器下生效。

**备注：** 下文中用“手指”表示与平面的交互，当然触控笔等也是可行的。

### 创建画布

```html
<canvas id="canvas" width="600" height="600" style="border:solid black 1px;">
  你的浏览器不支持 canvas 元素。
</canvas>
<br />
日志：
<pre id="log" style="border: 1px solid #ccc;"></pre>
```

### 设置事件处理器

当页面加载时，下文的 `startup()` 函数由 `window.onload` 属性触发。

```js
window.onload = function startup() {
  const el = document.getElementsByTagName("canvas")[0];
  el.addEventListener("touchstart", handleStart, false);
  el.addEventListener("touchend", handleEnd, false);
  el.addEventListener("touchmove", handleMove, false);
  log("初始化成功。");
};
```

该函数为 `<canvas>` 元素设置了所有相关的事件监听器，使事件在触发时能够得到处理。

#### 跟踪新触摸

我们将跟踪当前存在的所有触摸点。

```js
const ongoingTouches = [];
```

当 `touchstart` 事件触发时，平面上即出现一个新的触摸点，继而调用 `handleStart()` ：

```js
function handleStart(evt) {
  evt.preventDefault();
  console.log("触摸开始。");
  const el = document.getElementsByTagName("canvas")[0];
  const ctx = el.getContext("2d");
  const touches = evt.changedTouches;

  for (let i = 0; i < touches.length; i++) {
    console.log("开始第 " + i + " 个触摸 ...");
    ongoingTouches.push(copyTouch(touches[i]));
    const color = colorForTouch(touches[i]);
    ctx.beginPath();
    ctx.arc(touches[i].pageX, touches[i].pageY, 4, 0, 2 \* Math.PI, false);
    // 在起点画一个圆。
    ctx.fillStyle = color;
    ctx.fill();
    console.log("第 " + i + " 个触摸已开始。");
  }
}
```

`event.preventDefault()` 阻止了浏览器继续处理触摸（和鼠标）事件。然后我们取得上下文，从事件的 `TouchEvent.changedTouches` 属性中获得已改变的触摸点列表。

上述列表中所有的 `Touch` 对象即为当前所有活动的触摸点，把它们置于一个数组中，然后为每个触摸绘制起点。我们设置线条宽度为四像素，所以恰好会绘制一个半径为 4 像素的圆。

#### 当触摸移动时绘制

在触摸平面上移动一根或者几根手指会触发 `touchmove` 事件，从而将调用`handleMove()` 函数。本例中这个函数用于更新触摸点信息，并为每个触摸点从之前位置到当前位置之间绘制直线。

```js
function handleMove(evt) {
  evt.preventDefault();
  const el = document.getElementsByTagName("canvas")[0];
  const ctx = el.getContext("2d");
  const touches = evt.changedTouches;

  for (let i = 0; i < touches.length; i++) {
    const color = colorForTouch(touches[i]);
    const idx = ongoingTouchIndexById(touches[i].identifier);

    if (idx >= 0) {
      log("继续第 " + idx + "个触摸。");
      ctx.beginPath();
      log(
        "ctx.moveTo(" +
          ongoingTouches[idx].pageX +
          ", " +
          ongoingTouches[idx].pageY +
          ");",
      );
      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
      log("ctx.lineTo(" + touches[i].pageX + ", " + touches[i].pageY + ");");
      ctx.lineTo(touches[i].pageX, touches[i].pageY);
      ctx.lineWidth = 4;
      ctx.strokeStyle = color;
      ctx.stroke();

      ongoingTouches.splice(idx, 1, copyTouch(touches[i])); // 切换触摸信息
      console.log(".");
    } else {
      log("无法确定下一个触摸点。");
    }
  }
}
```

这个函数不仅对所有已改变的触摸点进行了遍历，还从缓存的触摸信息数组中得到了每个触摸点要绘制的新线段的起点。这是通过读取每个触摸点的 `Touch.identifier` 属性实现的。对每个触摸点而言，该属性是个唯一的整数，且手指接触表面的整个过程中，这个属性保持不变。

这样我们就可以取得每个触摸点之前位置的坐标，并且使用恰当的上下文方法绘制片段，从而将新旧两个位置连接起来。

当片段绘制完毕后，我们调用 `Array.splice()` 将 `ongoingTouches` 数组中触摸点之前的信息替换为当前信息。

#### 触摸结束处理

用户的手指从表面抬起时将触发 `touchend` 事件。我们通过调用下面的 `handleEnd()` 函数来处理此类事件。这个函数的工作就是为每个结束的触摸点绘制最后一个片段，然后将触摸点从 `ongoingTouches` 数组中移除。

```js
function handleEnd(evt) {
  evt.preventDefault();
  log("触摸结束。");
  const el = document.getElementsByTagName("canvas")[0];
  const ctx = el.getContext("2d");
  touches = evt.changedTouches;

  for (let i = 0; i < touches.length; i++) {
    const color = colorForTouch(touches[i]);
    const idx = ongoingTouchIndexById(touches[i].identifier);

    if (idx >= 0) {
      ctx.lineWidth = 4;
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.moveTo(ongoingTouches[idx].pageX, ongoingTouches[idx].pageY);
      ctx.lineTo(touches[i].pageX, touches[i].pageY);
      ctx.fillRect(touches[i].pageX - 4, touches[i].pageY - 4, 8, 8);
      // 在终点画一个正方形
      ongoingTouches.splice(idx, 1); // 用完后移除
    } else {
      log("无法确定要结束哪个触摸点。");
    }
  }
}
```

这个函数与上一个很相像，唯一的实质性区别就是在调用 `Array.splice()` 时，我们把用过的触摸实体从 `ongoingTouches` 数组中直接移除了，不再添加更新信息。对这个触摸点的跟踪随之终止。

#### 触摸取消处理

如果用户的手指不小心滑入浏览器界面，或者触摸需要取消时，会触发 `touchcancel` 事件。从而会调用下面的 `handleCancel()` 函数：

```js
function handleCancel(evt) {
  evt.preventDefault();
  console.log("触摸取消。");
  const touches = evt.changedTouches;

  for (let i = 0; i < touches.length; i++) {
    const idx = ongoingTouchIndexById(touches[i].identifier);
    ongoingTouches.splice(idx, 1); // 用完后移除
  }
}
```

这里的想法是立刻结束触摸，所以我们直接从 `ongoingTouches` 数组中将其移除，而不去绘制最后的片段。

### 便捷函数

本例中使用了几个便捷函数，有必要简单了解一下，对理解其他代码很有帮助。

#### 为每个触摸点选择一个颜色

为了区分每个触摸点绘制的内容，我们引入 `colorForTouch()` 函数，根据每个触摸点所独有的标记设定一个颜色。这个标记在这里可能是一个无意义的数字，但我们至少可以利用它“对于每个触摸点的值都不同”这一特性。

```js
function colorForTouch(touch) {
  let r = touch.identifier % 16;
  let g = Math.floor(touch.identifier / 3) % 16;
  let b = Math.floor(touch.identifier / 7) % 16;
  r = r.toString(16); // 转换为十六进制字符串
  g = g.toString(16); // 转换为十六进制字符串
  b = b.toString(16); // 转换为十六进制字符串
  const color = "#" + r + g + b;
  log("identifier " + touch.identifier + " 触摸的颜色为：" + color);
  return color;
}
```

这个函数返回一个表示颜色的字符串，可以在调用 `<canvas>` 的函数时使用。比如，若 `Touch.identifier` 的值为 10，则返回的字符串为 "#aaa"。

**警告：** 这里的 `colorForTouch()` 不是一个好主意。`Touch.identifier` 是一个实验性属性，存在兼容性问题，不同浏览器之间实现方法不同，因此会得到不同的结果。

#### 拷贝触摸对象

有些浏览器（比如 mobile Safari）会在不同事件之间复用触摸点对象，因此只复制所需的部分，要优于引用整个对象。

```js
function copyTouch(touch) {
  return {
    identifier: touch.identifier,
    pageX: touch.pageX,
    pageY: touch.pageY,
  };
}
```

#### 查找触摸点

`ongoingTouchIndexById()` 函数通过遍历 `ongoingTouches` 数组来寻找与给定标记相匹配的触摸点，返回该触摸点在数组中的下标。

```js
function ongoingTouchIndexById(idToFind) {
  for (let i = 0; i < ongoingTouches.length; i++) {
    const id = ongoingTouches[i].identifier;

    if (id == idToFind) {
      return i;
    }
  }
  return -1; // 未找到
}
```

#### 显示后台操作记录
```

function log(msg) {
  const p = document.getElementById('log');
  p.innerHTML = msg + "\n" + p.innerHTML;
}
```

如果你的浏览器支持触摸，就可以 在线试用。

jsFiddle 上的示例

附加信息
----

本节提供了在 web 应用中处理触摸事件的其他信息。

### 处理点击

由于在 `touchstart`（或系列 `touchmove` 事件里的首个）中调用 `preventDefault()` 也会阻止相应的鼠标事件的触发，因此一般情况下我们在`touchmove` 而不是 `touchstart` 中调用它，这样，鼠标事件仍可正常触发，链接等部件也可继续工作。有些框架采取了一个替代方案，使用触摸事件代替鼠标事件来达到相同目的。 (下面的示例过于简单，可能产生奇怪的行为。这里仅仅作为一个引导。)

```js
function onTouch(evt) {
  evt.preventDefault();
  if (
    evt.touches.length > 1 ||
    (evt.type == "touchend" && evt.touches.length > 0)
  )
    return;

  const newEvt = document.createEvent("MouseEvents");
  let type = null;
  let touch = null;

  switch (evt.type) {
    case "touchstart":
      type = "mousedown";
      touch = evt.changedTouches[0];
      break;
    case "touchmove":
      type = "mousemove";
      touch = evt.changedTouches[0];
      break;
    case "touchend":
      type = "mouseup";
      touch = evt.changedTouches[0];
      break;
  }

  newEvt.initMouseEvent(
    type,
    true,
    true,
    evt.originalTarget.ownerDocument.defaultView,
    0,
    touch.screenX,
    touch.screenY,
    touch.clientX,
    touch.clientY,
    evt.ctrlKey,
    evt.altKey,
    evt.shiftKey,
    evt.metaKey,
    0,
    null,
  );
  evt.originalTarget.dispatchEvent(newEvt);
}
```

### 只在第二次触摸时调用 preventDefault()

为了阻止页面产生类似 pinchZoom 的行为，可以通过“在系列触摸点的第二个调用 `preventDefault()`”技术来实现。但是该技术的行为并没有在触摸事件的标准中做出完整定义，并且在不同浏览器中会产生不同行为（比如，iOS 将阻止缩放，但允许二指平移；Android 允许缩放但阻止平移；Opera 和 Firefox 目前会阻止所有缩放和平移操作）。目前，对于此类情况最好依靠 `meta viewport` 来阻止缩放，而不要依赖于上述行为。

规范
--

| Specification |
| --- |
| Touch Events  |

浏览器兼容性
------

### `Touch`

### api.Touch

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TouchEvent

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.TouchList

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### Firefox，触摸事件以及多进程（e10s）

在 Firefox 中，触摸事件随 e10s（electrolysis 即 多进程 Firefox）的禁用而禁用。e10s 在 Firefox 中默认为可用，但可以在某些特定情形下关闭它，比如在安装一些要求禁用 e10s 的工具或扩展时。这意味着即使在支持触屏的桌面或便携设备上，触摸事件也可能失效。

你可以使用 `about:support` 查看“应用程序概要”部分中“多进程窗口”一栏来确定 e10s 是否启用。1/1 表示启用，0/1 表示禁用。

如果你想强制性的开启 e10s（来显式重新启用触摸事件支持），你需要使用 about:config 创建一个布尔类型的设置 `browser.tabs.remote.force-enable`，将它设置为 `true`，重启浏览器，e10s 将始终启用而不受其他设置的影响。


DecompressionStream - Web API 接口参考

DecompressionStream
===================

Compression Streams API 的 **`DecompressionStream`** 接口是一个用于解压缩数据流的 API。

构造函数
----

`DecompressionStream()`

创建一个新 `DecompressionStream`。

实例属性
----

`DecompressionStream.readable`

返回由此对象控制的 `ReadableStream` 实例。

`DecompressionStream.writable`

返回由此对象控制的 `WritableStream` 实例。

示例
--

在此示例中，使用 gzip 对 blob 进行解压缩。

```js
const ds = new DecompressionStream("gzip");
const decompressedStream = blob.stream().pipeThrough(ds);
```

规范
--

| Specification |
| --- |
| Compression Streams # decompression-stream |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


DOMStringMap - Web API 接口参考

DOMStringMap
============

**`DOMStringMap`** 接口用于 `HTMLElement.dataset` / `SVGElement.dataset` 属性，表示添加到元素的自定义属性的数据。

规范
--

| Specification |
| --- |
| HTML Standard # embedding-custom-non-visible-data-with-the-data-\*-attributes:domstringmap-3 |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `HTMLElement.dataset` / `SVGElement.dataset`
* 全局属性——`data-*`


TextEncoder - Web API 接口参考

TextEncoder
===========

**`TextEncoder`** 接受码位流作为输入，并提供 UTF-8 字节流作为输出。

**备注：** 此特性在 Web Worker 中可用

构造函数
----

`TextEncoder()`

返回一个新构造的 `TextEncoder`，它默认使用 UTF-8 编码将码位流转换成字节流。

属性
--

*`TextEncoder` 接口不继承任何属性。*

`TextEncoder.prototype.encoding` 只读

总是返回 `utf-8`。

方法
--

*`TextEncoder` 接口不继承任何方法。*

`TextEncoder.encode()`

接受一个字符串作为输入，返回一个包含 UTF-8 编码的文本的 `Uint8Array`。

`TextEncoder.encodeInto()`

接受一个字符串（编码的对象）和一个目标 `Uint8Array`（用于放入生成的 UTF-8 编码的文本）作为输入，并且返回一个指示编码进度的对象。此方法的性能可能会比更早出现的 `encode()` 方法好一些。

示例
--

```js
const encoder = new TextEncoder();
const view = encoder.encode("€");
console.log(view); // Uint8Array(3) [226, 130, 172]
```

规范
--

| Specification |
| --- |
| Encoding Standard # interface-textencoder |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `TextDecoder` 接口描述了逆操作。
* Node.js 从 v11.0.0 开始支持全局导出


Range - Web API 接口参考

Range
=====

**`Range`** 接口表示一个包含节点与文本节点的一部分的文档片段。

可以使用 `Document.createRange` 方法创建 Range。也可以用 `Selection` 对象的 `getRangeAt()` 方法或者 `Document` 对象的 `caretRangeFromPoint()` 方法获取 Range 对象。

还可以用 `Range()` 构造函数。

属性
--

*没有继承的属性。*

`Range.collapsed` 只读

返回一个表示 `Range` 的起始位置和终止位置是否相同的`布尔值` (en-US)。

`Range.commonAncestorContainer` 只读

返回完整包含 `startContainer` 和 `endContainer` 的、最深一级的`节点`。

`Range.endContainer` 只读

返回包含 `Range` 终点的`节点`。

`Range.endOffset` 只读

返回一个表示 `Range` 终点在 `endContainer` 中的位置的数字。

`Range.startContainer` 只读

返回包含 `Range` 开始的`节点`。

`Range.startOffset` 只读

返回一个数字，表示 `Range` 在 `startContainer` 中的起始位置。

构造函数
----

`Range()`

返回一个以全局（global）`Document` 作为起点与终点的 `Range` 对象。

方法
--

*该接口没有继承的方法。*

`Range.collapse()`

将 `Range` 折叠到其边界的端点。

`Range.compareBoundaryPoints()` (en-US)

将该 `Range` 的边界与另一个 `Range` 的边界进行比较

`Range.compareNode()` (en-US)
已弃用

非标准

返回一个常量，表示`节点`是否在 `Range` 的前、后、中、外。

`Range.comparePoint()` (en-US)

返回 -1、0 或 1，分别表示端点在 `Range` 之前、内部还是之后。

`Range.cloneContents()`

返回一个复制 `Range` 中所有节点的`文档片段`。

`Range.cloneRange()`

返回一个拥有和原 `Range` 对象相同端点的克隆的 `Range` 对象。

`Range.createContextualFragment()`

返回从给定的代码字符串创建的`文档片段`。

`Range.deleteContents()`

从 `Document` 中移除 `Range` 内容。

`Range.detach()` (en-US)

将 `Range` 从使用状态释放，提高性能。

`Range.extractContents()`

将 `Range` 的内容从文档树移动到一个`文档片段`。

`Range.getBoundingClientRect()`

返回一个 `DOMRect` 对象，其绑定了 `Range` 的整个内容；这将是通过 `range.getClientRects()` 返回所有边界矩形集合的其中之一。

`Range.getClientRects()`

返回一个 `DOMRect` 列表对象，该列表汇总了 `Range` 中所有元素的 `Element.getClientRects()` 返回结果。

`Range.isPointInRange()` (en-US)

返回一个 `boolean`，表示给点端点是否在 `Range` 中。

`Range.insertNode()`

在 `Range` 开头插入一个`节点`。

`Range.intersectsNode()`

返回一个 `boolean`，表示给定的节点是否与 `Range` 相交。

`Range.selectNode()`

设置 `Range` 包含某个`节点`及其他的内容。

`Range.selectNodeContents()`

设置 `Range` 包含某个`节点`的内容。

`Range.setEnd()`

设置 `Range` 的终点。

`Range.setStart()`

设置 `Range` 的起点。

`Range.setEndAfter()` (en-US)

以另一个`节点`为基准，设置 `Range` 的终点位置。

`Range.setEndBefore()` (en-US)

以另一个`节点`为基准，设置 `Range` 的终点位置。

`Range.setStartAfter()` (en-US)

以另一个`节点`为基准，设置 `Range` 的起点位置。

`Range.setStartBefore()`

以另一个`节点`为基准，设置 `Range` 的起点位置。

`Range.surroundContents()`

将 `Range` 中的内容移动到一个新的`节点`。

`Range.toString()` (en-US)

返回 `Range` 中的文本

规范
--

| Specification |
| --- |
| DOM Standard # interface-range |
| DOM Parsing and Serialization # extensions-to-the-range-interface |
| CSSOM View Module # extensions-to-the-range-interface |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* DOM 接口索引


Response - Web API 接口参考

Response
========

Fetch API 的 `Response` 接口呈现了对一次请求的响应数据。

你可以使用 `Response.Response()` 构造函数来创建一个 `Response` 对象，但通常更可能遇到的情况是，其他的 API 操作返回了一个 Response 对象。例如一个 service worker 的 `Fetchevent.respondWith`，或者一个简单的 `GlobalFetch.fetch()`。

构造函数
----

`Response()`

创建一个新的 `Response` 对象。

属性
--

`Response.headers` 只读

包含此 Response 所关联的 `Headers` 对象。

`Response.ok` 只读

包含了一个布尔值，标示该 Response 成功（HTTP 状态码的范围在 200-299）。

`Response.redirected` 只读

表示该 Response 是否来自一个重定向，如果是的话，它的 URL 列表将会有多个条目。

`Response.status` 只读

包含 Response 的状态码（例如 `200` 表示成功）。

`Response.statusText` (en-US) 只读

包含了与该 Response 状态码一致的状态信息（例如，OK 对应 `200`）。

`Response.type` 只读

包含 Response 的类型（例如，`basic`、`cors`）。

`Response.url` 只读

包含 Response 的 URL。

`Response.useFinalURL`

包含了一个布尔值，来标示这是否是该 Response 的最终 URL。

`Response` 实现了 `Body` 接口，所以以下属性亦可用：

`Response.body` 只读

一个简单的 getter，用于暴露一个 `ReadableStream` 类型的 body 内容。

`Response.bodyUsed` 只读

包含了一个`布尔值` (en-US)来标示该 Response 是否读取过 `Body`。

方法
--

`Response.clone()`

创建一个 `Response` 对象的克隆。

`Response.error()`

返回一个绑定了网络错误的新的 `Response` 对象。

`Response.redirect()`

用另一个 URL 创建一个新的 `Response`。

`Response` 实现了 `Body` 接口，所以以下方法同样可用：

`Body.arrayBuffer()` (en-US)

读取 `Response` 对象并且将它设置为已读（因为 Responses 对象被设置为了 stream 的方式，所以它们只能被读取一次），并返回一个被解析为 `ArrayBuffer` 格式的 Promise 对象。

`Body.blob()` (en-US)

读取 `Response` 对象并且将它设置为已读（因为 Responses 对象被设置为了 stream 的方式，所以它们只能被读取一次），并返回一个被解析为 `Blob` 格式的 Promise 对象。

`Body.formData()` (en-US)

读取`Response` 对象并且将它设置为已读（因为 Responses 对象被设置为了 stream 的方式，所以它们只能被读取一次），并返回一个被解析为 `FormData` 格式的 Promise 对象。

`Body.json()` (en-US)

读取 `Response` 对象并且将它设置为已读（因为 Responses 对象被设置为了 stream 的方式，所以它们只能被读取一次），并返回一个被解析为 `JSON` 格式的 Promise 对象。

`Body.text()` (en-US)

读取 `Response` 对象并且将它设置为已读（因为 Responses 对象被设置为了 stream 的方式，所以它们只能被读取一次），并返回一个被解析为 `USVString` 格式的 Promise 对象。

示例
--

在我们的基础实例 (点击运行) 中，我们使用了一个简单的函数调用，调用了 `fetch()` 函数来获取一张图片并将其显示在 HTML 的 IMG 标签中，`fetch()` 函数返回了一个 Promise，它使用与资源获取操作相关联的 Response 对象进行解析。你会注意到，由于我们正在请求一张图片，我们需要运行 `Body.blob` (en-US)（`Response` 实现了），以为响应提供正确的 MIME 类型。

```js
const image = document.querySelector(".my-image");
fetch("flowers.jpg")
  .then(function (response) {
    return response.blob();
  })
  .then(function (blob) {
    const objectURL = URL.createObjectURL(blob);
    image.src = objectURL;
  });
```

你也可以使用 `Response.Response()` 这样的构造方法，来创建自定义的 `Response` 对象：

```js
const response = new Response();
```

规范
--

| Specification |
| --- |
| Fetch Standard # response-class |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* ServiceWorker API
* HTTP 访问控制（CORS）
* HTTP


HTMLButtonElement - Web API 接口参考

HTMLButtonElement
=================

**`HTMLButtonElement`** 接口提供操作 button 元素（除了 `<button>` 对象，这个接口对继承了该对象的元素也有效）的属性和方法。

属性
--

*从父对象`HTMLElement`继承的属性。*

| 名字 | 类型 | 描述 |
| --- | --- | --- |
| `accessKey` | `DOMString` | 一个键盘字符构成的字符串，表明用哪个键盘字符能够访问这个按钮。 |
| `autofocus` | `Boolean` (en-US) | 这个控件是否可以在页面加载时自动得到焦点。但用户选择了其他焦点除外。只有和表单关联的按钮该特性才有效。 |
| `disabled` | `Boolean` (en-US) | 这个控件是否被禁用。被禁用的控件不接受任何输入和点击。 |
| `form` 只读  | `HTMLFormElement` |
 这个按钮所关联的表单元素。如果这个按钮是一个表单元素的后代元素，那么这个属性的值就是那个表单元素。如果这个按钮不是一个表单元素的后代元素，那么这个数学可以是任意同文档中的表单元素，或者是
 `null` 表明它没有关联任何表单。
  |
| `formAction` | `DOMString` |
 一个处理提交信息的 URI 资源地址。如果指定该属性，会覆盖拥有该元素的 `<form>`
 元素的 `action` 属性。
  |
| `formEncType` | `DOMString` |
 表单要提交给服务器处理的内容的类型。如果指定该属性，会覆盖拥有该元素的 `<form>`
 元素的 `enctype` 属性。
  |
| `formMethod` | `DOMString` |
 浏览器提交表单内容的 HTTP 方法。如果指定该属性，会覆盖拥有该元素的 `<form>`
 元素的 `method` 属性。
  |
| `formNoValidate` | `Boolean` (en-US) |
 表明这个表单提交时是否需要验证。如果指定该属性，会覆盖拥有该元素的 `<form>`
 元素的 `novalidate` 属性。
  |
| `formTarget` | `DOMString` |
 一个名字或关键字，用于表明显示服务器响应的页面。如果指定该属性，会覆盖拥有该元素的 `<form>`
 元素的 `target` 属性。
  |
| `labels` 只读  | `NodeList` |
 一个 `<label>`
 元素表，说明哪些标签是归属这个按钮的。
  |
| `menu`
实验性
 | `HTMLMenuElement` (en-US) | 如果该按钮 `type="menu"`，被点击的时候应该显示的菜单。 |
| `name` | `DOMString` | 提交到服务器时表单描述该对象的 name。如果指定该属性，不能使用空字符串。 |
| `tabIndex` | long | 用于表示该元素在 tab 按钮跳动过程中的序号的一个数字。 |
| `type` | `DOMString` | 表明按钮的行为。这个属性是枚举类型，可以是以下的值：
 * `"submit"`：这个按钮会提交表单。如果不指定该属性，这是默认值。可以动态改为空值或者无效值。
* `"reset"`：用于重置（清空）表单。
* `"button"`：什么都不做的按钮。通常通过 Javascript 挂载事件。
* `"menu"`：显示菜单的按钮

实验性
。
 |
| `validationMessage` 只读  | `DOMString` | 报告该控件不满足验证要求的，提示给用户的看的信息。如果这个控件没有验证约束（`willValidate` 值为 `false`），或者满足验证的要求，那么这个属性为空字符串。 |
| `validity` 只读  | `ValidityState` | 这个控件当前的验证状态。 |
| `value` | `DOMString` | 这个控件当前的表单值。 |
| `willValidate` | `Boolean` (en-US) |
 表明这个按钮是否需要在提交前进行验证。如果不需要，这个属性值为`false`
 。
  |

方法
--

*从父对象`HTMLElement`继承的方法。*

| 名字 | 返回类型 | 描述 |
| --- | --- | --- |
| `checkValidity()` | `Boolean` (en-US) | 对按钮元素不支持。 |
| `setCustomValidity(in DOMString error)` | `void` | 对按钮元素不支持。 |

在基于 Gecko 的浏览器中，在表单验证时会使用 `:-moz-submit-invalid` (en-US) 伪类修饰提交按钮。

规范
--

| Specification |
| --- |
| HTML Standard # htmlbuttonelement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 实现该接口的 HTML 元素：`<button>`


PictureInPictureWindow - Web API 接口参考

PictureInPictureWindow
======================

\*\*`PictureInPictureWindow`\*\*接口是一个对象，它可以通过编程的方式获得浮动视频窗口的宽度和高度，并调整浮动视频窗口的大小。

使用`HTMLVideoElement.requestPictureInPicture()`返回一个具有此接口的 promise 值

属性
--

*`PictureInPictureWindow` 接口不继承任何属性。*

`PictureInPictureWindow.width` (en-US) 只读

获取浮动视频窗宽度。

`PictureInPictureWindow.height` (en-US) 只读

获取浮动视频窗高度。

Methods
-------

*The `PictureInPictureWindow` interface doesn't inherit any methods.*

Events
------

**The `PictureInPictureWindow` interface doesn't inherit any events.**

`PictureInPictureWindow.resize` (en-US)

Sent to a `PictureInPictureWindow` when the floating video window is resized. The associated event handler is `PictureInPictureWindow.onresize` (en-US).

Examples
--------

Given a `<button>` and a `<video>`, clicking the button will make the video enter the picture-in-picture mode; we then attach an event to print the floating video window dimensions to the console.

```js
const button = document.querySelector("button");
const video = document.querySelector("video");

function printPipWindowDimensions(evt) {
  const pipWindow = evt.target;
  console.log(
    `The floating window dimensions are: ${pipWindow.width}x${pipWindow.height}px`,
  );
  // will print:
  // The floating window dimensions are: 640x360px
}

button.onclick = function () {
  video.requestPictureInPicture().then((pictureInPictureWindow) => {
    pictureInPictureWindow.onresize = printPipWindowDimensions;
  });
};
```

Specifications
--------------

| Specification |
| --- |
| Picture-in-Picture # interface-picture-in-picture-window |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `Picture-in-Picture_API`


Stream API - Web API 接口参考

Stream API
==========

Stream API 允许 JavaScript 以编程方式访问从网络接收的数据流，并且允许开发人员根据需要处理它们。

**备注：** 此特性在 Web Worker 中可用

概念和用法
-----

流会将你想要从网络接受的资源分成一个个小的分块，然后按位处理它。这正是浏览器在接收用于显示 web 页面的资源时做的事情——视频缓冲区和更多的内容可以逐渐播放，有时候随着内容的加载，你可以看到图像逐渐地显示。

但曾经这些对于 JavaScript 是不可用的。以前，如果我们想要处理某种资源（如视频、文本文件等），我们必须下载完整的文件，等待它反序列化成适当的格式，然后在完整地接收到所有的内容后再进行处理。

随着流在 JavaScript 中的使用，一切发生了改变——只要原始数据在客户端可用，你就可以使用 JavaScript 按位处理它，而不再需要缓冲区、字符串或 blob。

![](/zh-CN/docs/Web/API/Streams_API/concept.png)

还有更多的优点——你可以检测流何时开始或结束，将流链接在一起，根据需要处理错误和取消流，并对流的读取速度做出反应。

流的基础应用围绕着使响应可以被流处理展开。例如，一个成功的 fetch 请求返回的响应体可以暴露为 `ReadableStream`，之后你可以使用 `ReadableStream.getReader()` 创建一个 reader 读取它，使用 `ReadableStream.cancel()` 取消它等等。

更复杂的应用包括使用 `ReadableStream()` 构造函数创建你自己的流，例如进入 service worker 去处理流。

你也可以使用 `WritableStream` 将数据写入流。

**备注：** 你可以在这些文章中找到关于流理论的更多细节和实践——Stream API 概念、使用可读流、使用可读字节流 (en-US)，以及使用可写流 (en-US)。

Stream 接口
---------

### 可读流

`ReadableStream`

表示数据的可读流。用于处理 Fetch API 返回的响应，或者开发者自定义的流（例如通过 `ReadableStream()` 构造的流）。

`ReadableStreamDefaultReader`

表示默认 reader，用于读取来自网络的数据流（例如 fetch 请求）。

`ReadableStreamDefaultController`

表示一个 controller，用于控制 `ReadableStream` 的状态及内部队列。默认的 controller 用于处理非字节流。

### 可写流

`WritableStream`

为将流写入目的地（称为接收器）的过程，提供了一个标准抽象。内置了背压和队列机制。

`WritableStreamDefaultWriter`

表示默认 writer，用于将分块的数据写入可写流中。

`WritableStreamDefaultController`

表示一个 controller，用于控制 `WritableStream` 的状态。当创建一个 `WritableStream` 时，对应的 `WritableStreamDefaultController` 实例会被提供给底层的接收器供其操作。

### 转换流

`TransformStream`

表示一组可转化的数据。

`TransformStreamDefaultController`

提供操作和转换流关联的 `ReadableStream` 和 `WritableStream` 的方法。

### 流相关的 API 和操作

`ByteLengthQueuingStrategy`

当构建流时，提供建立流时所需的内置字节队列策略。

`CountQueuingStrategy`

当构建流时，提供建立流时所需的块计数队列策略。

### 其他 API 扩展

`Request`

当构造一个新的 `Request` 对象后，你可以给它的 `RequestInit` 中的 `body` 属性传入一个 `ReadableStream`。这个 `Request` 对象就可以被传入 `fetch()` 中，开始接收流。

`Response.body`

一个成功的 fetch request 响应体会默认暴露为 `ReadableStream`，从而可以采用相应的 reader 来处理等。

### 字节流相关的接口

`ReadableStreamBYOBReader` (en-US)

表示一个 BYOB（“带你自己的缓冲区”）reader，它可以用于读取由开发人员提供的流数据（例如一个自定义的 `ReadableStream()`）。

`ReadableByteStreamController` (en-US)

表示一个 controller，用于控制 `ReadableStream` 的状态及内部队列。字节流 controller 用于处理字节流。

`ReadableStreamBYOBRequest` (en-US)

表示 `ReadableByteStreamController` (en-US) 中的 BYOB 拉取请求。

示例
--

我们创建了流的示例目录，以配合 Stream API 文档——参见 mdn/dom-examples/streams。示例如下：

* 简单的流 pump：此示例展示了如何消费流并且传递它的数据进入另一个。
* 转换一个 PNG 到灰度：这个示例展示了如何使用可读流将 PNG 转换到灰度。
* 简单随机流：这个示例展示了如何使用一个自定义流去生成随机字符串，并将将它们排入分块，然后重新读取它们。
* 简单拷贝示例：这个示例由简单随机流扩展，展示了一个流如何被拷贝为两个并且生成的流可以被独立的读取。
* 简单 writer：这个示例展示了如何写入可写流，然后解码流并将流内容写入 UI。
* 解压 PNG 分块：此示例展示了如何使用 `pipeThrough()` 通过将 PNG 文件的数据转换为 PNG 分块流来将 ReadableStream 转换为其他数据类型的流。

来自其他开发人员的示例：

* Stream、Service Worker 以及 Fetch 进度指标.
规范
--

| Specification |
| --- |
| Streams Standard # rs-class |
| Streams Standard # ws-class |

浏览器兼容性
------

### api.ReadableStream

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.WritableStream

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* Stream API 概念
* 使用可读流
* 使用可读字节流 (en-US)
* 使用可写流 (en-US)