Set.prototype.keys() - JavaScript

Set.prototype.keys()
====================

`Set` 实例的 **`keys()`** 方法是 `values()` 方法的别名。

语法
--

```js
keys()
```

### 参数

无。

### 返回值

一个新的可迭代迭代器对象。

示例
--

### 使用 keys()

`keys()` 方法完全等价于 `values()` 方法。

```js
const mySet = new Set();
mySet.add("foo");
mySet.add("bar");
mySet.add("baz");

const setIter = mySet.keys();

console.log(setIter.next().value); // "foo"
console.log(setIter.next().value); // "bar"
console.log(setIter.next().value); // "baz"
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.keys |

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

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

参见
--

* `Set.prototype.entries()`
* `Set.prototype.values()`


Set.prototype.size - JavaScript

Set.prototype.size
==================

`Set` 实例的 **`size`** 访问器属性将返回该集合中（唯一的）元素的个数。

尝试一下
----

描述
--

`size` 的值是一个整数，表示 `Set` 对象有多少条目。`size` 的 set 访问函数是 `undefined`；你无法改变这个属性。

示例
--

### 使用 size

```js
const mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add("some text");

console.log(mySet.size); // 3
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-get-set.prototype.size |

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

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

参见
--

* `Set`


Set.prototype.forEach() - JavaScript

Set.prototype.forEach()
=======================

`Set` 实例的 **`forEach()`** 方法按插入顺序为该集合中的每个值执行一次提供的函数。

尝试一下
----

语法
--

```js
forEach(callbackFn)
forEach(callbackFn, thisArg)
```

### 参数

`callback`

为集合中每个元素执行的函数，使用以下参数调用该函数：

`value`

每次迭代的值。

`key`

每次迭代的键。始终与 `value` 相同。

`set`

正在迭代的集合。

`thisArg` 可选

执行 `callbackFn` 时用作 `this` 的值。

### 返回值

无（`undefined`）。

描述
--

`forEach()` 方法对 `Set` 对象中实际存在的每个值执行一次提供的 `callback`。对于已删除的值，不会调用它。但是，它会对存在但值为 `undefined` 的值执行。

`callback` 被调用时带有**三个参数**：

* **元素的值**
* **元素的键**
* **被遍历的 `Set`**

`Set` 对象中没有键，所以前两个参数都是 `Set` 中包含的**值**。这是为了与 `Map` 和 `Array` 的 `forEach()` 方法保持一致。

如果提供了一个 `thisArg` 参数给 `forEach` 函数，则参数将会作为回调函数中的 `this`值。否则 `this` 值为 `undefined`。回调函数中 `this` 的绑定是根据函数被调用时通用的 `this` 绑定规则来决定的。

每个值都访问一次，除非在 `forEach()` 完成之前删除并重新添加它。在访问之前删除的值不会调用 `callback`。在 `forEach()` 完成之前添加的新值将被访问。

`forEach()` 对 `Set` 对象中的每个元素执行一次 `callback` 函数；它没有返回值。

示例
--

### 输出集合对象的内容

以下代码依次打印 `Set` 对象的元素：

```js
function logSetElements(value1, value2, set) {
  console.log(`s[${value}] = ${value2}`);
}

new Set(["foo", "bar", undefined]).forEach(logSetElements);

// logs:
// "s[foo] = foo"
// "s[bar] = bar"
// "s[undefined] = undefined"
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.foreach |

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

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

参见
--

* `Array.prototype.forEach()`
* `Map.prototype.forEach()`


Set() 构造函数 - JavaScript

Set() 构造函数
==========

**`Set()`** 构造函数创建 `Set` 对象。

尝试一下
----

语法
--

```js
new Set()
new Set(iterable)
```

**备注：** `Set()` 只能用 `new` 构建。试图在没有 `new` 的情况下调用它，会抛出 `TypeError`。

### 参数

`iterable` 可选

如果传入一个可迭代对象，它的所有元素将不重复地被添加到新的 `Set` 中。如果不指定此参数或其值为 `null`，则新的 `Set` 为空。

### 返回值

一个新的 `Set` 对象。

示例
--

### 使用 `Set` 对象

```js
const mySet = new Set();

mySet.add(1); // Set [ 1 ]
mySet.add(5); // Set [ 1, 5 ]
mySet.add(5); // Set [ 1, 5 ]
mySet.add("some text"); // Set [ 1, 5, 'some text' ]
const o = { a: 1, b: 2 };
mySet.add(o);
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set-constructor |

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

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

参见
--

* `core-js` 中 `Set` 的 polyfill
* `Set`


Set.prototype[@@iterator]() - JavaScript

Set.prototype[@@iterator]()
===========================

`Set` 实例的 **`[@@iterator]()`** 方法实现了可迭代协议以允许 `Set` 对象被大多数期望可迭代对象的语法所使用，例如展开语法和 `for...of` 循环。它返回一个集合迭代器对象，它会以插入顺序生成集合的值。

该属性的初始值与 `Set.prototype.values()` 属性的初始值是同一个函数对象。

尝试一下
----

语法
--

```js
set[Symbol.iterator]()
```

### 参数

无。

### 返回值

与 `Set.prototype.values()` 返回值相同：一个新的可迭代迭代器对象，它会以插入顺序生成集合的值。

示例
--

### 使用 for...of 循环进行迭代

请注意，通常你不需要直接调用此方法。`@@iterator` 方法的存在使得 `Set` 对象可迭代，而像 `for...of` 循环这样的迭代语法会自动调用此方法以获取用于循环的迭代器。

```js
const mySet = new Set();
mySet.add("0");
mySet.add(1);
mySet.add({});

for (const v of mySet) {
  console.log(v);
}
```

### 手动控制迭代器

你仍然可以手动调用返回的迭代器对象的 `next()` 方法来获得最大程度的控制权。

```js
const mySet = new Set();
mySet.add("0");
mySet.add(1);
mySet.add({});

const setIter = mySet[Symbol.iterator]();

console.log(setIter.next().value); // "0"
console.log(setIter.next().value); // 1
console.log(setIter.next().value); // {}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype-@@iterator |

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

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

参见
--

* `Set`
* `Set.prototype.entries()`
* `Set.prototype.keys()`
* `Set.prototype.values()`
* `Symbol.iterator`
* 迭代协议


Set.prototype.entries() - JavaScript

Set.prototype.entries()
=======================

`Set` 实例的 **`entries()`** 方法返回一个新的*集合迭代器*对象，该对象包含了此集合中每个元素的 **`[value, value]` 数组**，按插入顺序排列。`Set` 对象没有类似于 `Map` 对象中的 `key`。因此，为了保持 API 与 `Map` 对象类似，这里每个 *entry* 的 *key* 和 *value* 都相同，所以返回的数组为 `[value, value]`。

尝试一下
----

语法
--

```js
entries()
```

### 参数

无。

### 返回值

一个新的可迭代迭代器对象。

示例
--

### 使用 entries()

```js
const mySet = new Set();
mySet.add("foobar");
mySet.add(1);
mySet.add("baz");

const setIter = mySet.entries();

console.log(setIter.next().value); // ["foobar", "foobar"]
console.log(setIter.next().value); // [1, 1]
console.log(setIter.next().value); // ["baz", "baz"]
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.entries |

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

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

参见
--

* `Set.prototype.keys()`
* `Set.prototype.values()`


get Set[@@species] - JavaScript

get Set[@@species]
==================

**`Set[@@species]`** 静态访问器属性是一个未使用的访问器属性，指定了如何复制 `Set` 对象。

语法
--

```js
Set[Symbol.species]
```

### 返回值

调用 `get @@species` 的构造函数的值（`this`）。返回值用于构造复制的 `Set` 实例。

描述
--

`@@species` 访问器属性返回 `Set` 对象的默认构造函数。子类构造函数可以覆盖它以更改构造函数赋值。

**备注：** 目前所有 `Set` 方法均未使用此属性。

示例
--

### 普通对象的 Species

`@@species` 属性返回默认构造函数，即 `Set` 的构造函数。

```js
Set[Symbol.species]; // 函数 Set()
```

### 派生对象的 Species

在一个自定义的 `Set` 子类（如 `MySet`）的实例中，`MySet` 的 `species` 是 `MySet` 构造函数。但是，你可能希望覆盖它，以便在派生类方法中返回父 `Set` 对象：

```js
class MySet extends Set {
  // 用父类 Set 构造函数覆盖 MySet 的 species
  static get [Symbol.species]() {
    return Set;
  }
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-get-set-@@species |

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

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

参见
--

* `Set`
* `Symbol.species`


Set.prototype.has() - JavaScript

Set.prototype.has()
===================

`Set` 实例的 **`has()`** 方法返回一个布尔值来指示对应的值是否存在于该集合中。

尝试一下
----

语法
--

```js
has(value)
```

### 参数

`value`

要测试是否存在于 `Set` 对象中的值。

### 返回值

如果 `Set` 对象中存在具有指定值的元素，则返回 `true`；否则返回 `false`。

示例
--

### 使用 has() 方法

```js
const mySet = new Set();
mySet.add("foo");

console.log(mySet.has("foo")); // true
console.log(mySet.has("bar")); // false

const set1 = new Set();
const obj1 = { key1: 1 };
set1.add(obj1);

console.log(set1.has(obj1)); // true
console.log(set1.has({ key1: 1 })); // false, 因为它们是不同的对象引用
console.log(set1.add({ key1: 1 })); // 现在 set1 包含 2 个条目
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.has |

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

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

参见
--

* `Set`
* `Set.prototype.add()`
* `Set.prototype.delete()`


Set.prototype.add() - JavaScript

Set.prototype.add()
===================

`Set` 实例的 **`add()`** 方法会在该集合中插入一个具有指定值的新元素，如果该 `Set` 对象中没有具有相同值的元素。

尝试一下
----

语法
--

```js
add(value)
```

### 参数

`value`

要添加到 `Set` 对象的元素的值。

### 返回值

添加了值的 `Set` 对象。

示例
--

### 使用 add() 方法

```js
const mySet = new Set();

mySet.add(1);
mySet.add(5).add("some text"); // 可以链式调用

console.log(mySet);
// Set [1, 5, "some text"]
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.add |

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

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

参见
--

* `Set`
* `Set.prototype.delete()`
* `Set.prototype.has()`


Set.prototype.values() - JavaScript

Set.prototype.values()
======================

`Set` 实例的 **`values()`** 方法返回一个新的*集合迭代器*对象，该对象包含此集合对象中每个元素的值，按插入顺序排列。

尝试一下
----

语法
--

```js
values()
```

### 参数

无。

### 返回值

一个新的可迭代迭代器对象。

示例
--

### 使用 values()

```js
const mySet = new Set();
mySet.add("foo");
mySet.add("bar");
mySet.add("baz");

const setIter = mySet.values();

console.log(setIter.next().value); // "foo"
console.log(setIter.next().value); // "bar"
console.log(setIter.next().value); // "baz"
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.values |

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

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

参见
--

* `Set.prototype.entries()`
* `Set.prototype.keys()`


Set.prototype.clear() - JavaScript

Set.prototype.clear()
=====================

`Set` 实例的 **`clear()`** 方法移除该集合中的所有元素。

尝试一下
----

语法
--

```js
clear()
```

### 参数

无。

### 返回值

无（`undefined`）。

示例
--

### 使用 clear() 方法

```js
const mySet = new Set();
mySet.add(1);
mySet.add("foo");

console.log(mySet.size); // 2
console.log(mySet.has("foo")); // true

mySet.clear();

console.log(mySet.size); // 0
console.log(mySet.has("foo")); // false
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-set.prototype.clear |

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

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

参见
--

* `Set`
* `Set.prototype.delete()`


AsyncFunction() 构造函数 - JavaScript

AsyncFunction() 构造函数
====================

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

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

* Learn more
* See full compatibility
* Report feedback
**`AsyncFunction()`** 构造函数创建一个新的 `AsyncFunction` 对象。

注意，`AsyncFunction` *不是*全局对象。它可以通过以下代码获取：

```js
const AsyncFunction = async function () {}.constructor;
```

`AsyncFunction()` 构造函数不能直接使用，并且所有在 `Function()` 描述中提到的注意事项都适用于 `AsyncFunction`。

语法
--

```js
new AsyncFunction(functionBody)
new AsyncFunction(arg1, functionBody)
new AsyncFunction(arg1, arg2, functionBody)
new AsyncFunction(arg1, arg2, /\* …, \*/ argN, functionBody)

AsyncFunction(functionBody)
AsyncFunction(arg1, functionBody)
AsyncFunction(arg1, arg2, functionBody)
AsyncFunction(arg1, arg2, /\* …, \*/ argN, functionBody)
```

**备注：** 无论是否使用 `new` 调用 `AsyncFunction()`，都可以创建一个新的 `AsyncFunction` 实例。

### 参数

参见 `Function()`。

示例
--

### 从 AsyncFunction() 构造函数创建异步函数

```js
function resolveAfter2Seconds(x) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

const AsyncFunction = async function () {}.constructor;

const fn = new AsyncFunction(
  "a",
  "b",
  "return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);",
);

fn(10, 20).then((v) => {
  console.log(v); // 4 秒过后，输出 30
});
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-async-function-constructor |

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

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

参见
--

* `async function` 声明
* `async function` 表达式
* `Function()` 构造函数


Promise.allSettled() - JavaScript

Promise.allSettled()
====================

**`Promise.allSettled()`** 静态方法将一个 Promise 可迭代对象作为输入，并返回一个单独的 `Promise`。当所有输入的 Promise 都已敲定时（包括传入空的可迭代对象时），返回的 Promise 将被兑现，并带有描述每个 Promise 结果的对象数组。

尝试一下
----

语法
--

```js
Promise.allSettled(iterable)
```

### 参数

`iterable`

一个以 promise 组成的可迭代对象（例如 `Array`）对象。

### 返回值

一个 `Promise`，其状态为：

* **已兑现（already fulfilled）**，如果传入的 `iterable` 为空的话。
* **异步兑现（asynchronously fulfill）**，当给定的 `iterable` 中所有 promise 已经敲定时（要么已兑现，要么已拒绝）。兑现的值是一个对象数组，其中的对象按照 `iterable` 中传递的 promise 的顺序，描述每一个 promise 的结果，无论完成顺序如何。每个结果对象都有以下的属性：

`status`

一个字符串，要么是 `"fulfilled"`，要么是 `"rejected"`，表示 promise 的最终状态。

`value`

仅当 `status` 为 `"fulfilled"`，才存在。promise 兑现的值。

`reason`

仅当 `status` 为 `"rejected"`，才存在，promsie 拒绝的原因。

如果传入的 `iterable` 是非空的，但不包含待定的（pending）promise，则返回的 promise 仍然是异步兑现的，而不是同步兑现。
描述
--

`Promise.allSettled()` 方法是 promise 并发方法之一。在你有多个不依赖于彼此成功完成的异步任务时，或者你总是想知道每个 promise 的结果时，使用 `Promise.allSettled()` 。

相比之下，如果任务相互依赖，或者如果你想在任何 promise 被拒绝时立即拒绝，`Promise.all()` 返回的 Promise 可能更合适。

示例
--

### 使用 Promise.allSettled()

```js
Promise.allSettled([
  Promise.resolve(33),
  new Promise((resolve) => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error("一个错误")),
]).then((values) => console.log(values));

// [
// { status: 'fulfilled', value: 33 },
// { status: 'fulfilled', value: 66 },
// { status: 'fulfilled', value: 99 },
// { status: 'rejected', reason: Error: 一个错误 }
// ]
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.allsettled |

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

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

参见
--

* `core-js` 中 `Promise.allSettled` 的 polyfill
* 使用 promise
* 使用 promise 的优雅异步编程
* `Promise`
* `Promise.all()`
* `Promise.any()`
* `Promise.race()`


Promise[@@species] - JavaScript

Promise[@@species]
==================

静态访问器属性 **`Promise[@@species]`** 返回用于构造 Promise 方法返回值的构造函数。

**警告：** `@@species` 的存在允许任意代码的执行，这可能会导致安全漏洞，并且使某些优化更加困难。引擎实现者正在调查是否删除此特性。如果可能的话，应避免依赖它。

语法
--

```js
Promise[Symbol.species]
```

### 返回值

`get @@species` 被调用时的构造函数 `this` 的值。返回值用于构造从创建新 Promise 的 Promise 链式方法的返回值。

描述
--

`@@species` 访问器属性返回 `Promise` 对象的默认构造函数。子类构造函数可以覆盖它以更改构造函数的赋值。默认实现基本上是这样的：

```js
// 以下是一个假设的基本实现，仅供说明
class Promise {
  static get [Symbol.species]() {
    return this;
  }
}
```

由于这种多态实现，派生子类的 `@@species` 默认情况下也会返回构造函数本身。

```js
class SubPromise extends Promise {}
SubPromise[Symbol.species] === SubPromise; // true
```

Promise 链式方法——`then()`、`catch()` 和 `finally()`——返回新的 Promise 对象。它们通过 `this.constructor[@@species]` 获取构造新 Promise 的构造函数。如果 `this.constructor` 为 `undefined`，或者 `this.constructor[@@species]` 为 `undefined` 或 `null`，则会使用默认的 `Promise()` 构造函数。否则，将使用 `this.constructor[@@species]` 返回的构造函数来构造新的 Promise 对象。

示例
--

### 普通对象中的 Species

`Symbol.species` 属性返回默认的构造函数，对于 `Promise` 来说，它的默认构造函数就是 `Promise` 构造函数本身。

```js
Promise[Symbol.species]; // [Function: Promise]
```

### 派生对象中的 Species

在自定义 `Promise` 子类的实例中，比如 `MyPromise`，`MyPromise` 的 species 是 `MyPromise` 构造函数本身。然而，你可能希望在派生类的方法中覆盖该属性，以便返回父类 `Promise` 对象。

```js
class MyPromise extends Promise {
  // 将 MyPromise 的 species 覆盖为父类 Promise 构造函数
  static get [Symbol.species]() {
    return Promise;
  }
}
```

默认情况下，Promise 方法将返回具有子类类型的 Promise。

```js
class MyPromise extends Promise {
  someValue = 1;
}

console.log(MyPromise.resolve(1).then(() => {}).someValue); // 1
```

通过覆盖 `@@species`，Promise 方法将返回基本的 `Promise` 类型。

```js
class MyPromise extends Promise {
  someValue = 1;
  static get [Symbol.species]() {
    return Promise;
  }
}

console.log(MyPromise.resolve(1).then(() => {}).someValue); // undefined
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-get-promise-@@species |

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

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

参见
--

* `Promise`
* `Symbol.species`


Promise.prototype.finally() - JavaScript

Promise.prototype.finally()
===========================

`Promise` 实例的 **`finally()`** 方法用于注册一个在 promise 敲定（兑现或拒绝）时调用的函数。它会立即返回一个等效的 `Promise` 对象，这可以允许你链式调用其他 promise 方法。

这可以让你避免在 promise 的 `then()` 和 `catch()` 处理器中重复编写代码。

尝试一下
----

语法
--

```js
finally(onFinally)
```

### 参数

`onFinally`

一个当 promise 敲定时异步执行的函数。它的返回值将被忽略，除非返回一个被拒绝的 promise。调用该函数时不带任何参数。

### 返回值

返回等效的 `Promise`。如果处理程序抛出错误或返回被拒绝的 promise，那么 `finally()` 返回的 promise 将以该值被拒绝。否则，处理程序的返回值不会影响原始 promise 的状态。

描述
--

如果你想在 promise 敲定时进行一些处理或者清理，无论其结果如何，那么 `finally()` 方法会很有用。

`finally()` 方法类似于调用 `then(onFinally, onFinally)`。然而，有几个不同之处：

* 创建内联函数时，你可以只将其传入一次，而不是强制声明两次或为其创建变量。
* `onFinally` 回调函数不接收任何参数。这种情况恰好适用于你*不关心*拒绝原因或兑现值的情况，因此无需提供它。
* `finally()` 调用通常是透明的，不会更改原始 promise 的状态。例如：
    + 与 `Promise.resolve(2).then(() => 77, () => {})` 不同，它返回一个最终会兑现为值 `77` 的 promise，而 `Promise.resolve(2).finally(() => 77)` 返回一个最终兑现为值 `2` 的 promise。
    + 类似地，与 `Promise.reject(3).then(() => {}, () => 88)` 不同，它返回一个最终兑现为值 `88` 的 promise，而 `Promise.reject(3).finally(() => 88)` 返回一个最终以原因 `3` 拒绝的 promise。

**备注：** 在 `finally` 回调函数中抛出错误（或返回被拒绝的 promise）仍会导致返回的 promise 被拒绝。例如，`Promise.reject(3).finally(() => { throw 99; })` 和 `Promise.reject(3).finally(() => Promise.reject(99))` 都以理由 `99` 拒绝返回的 promise。

与 `catch()` 一样，`finally()` 在内部调用其调用对象上的 `then` 方法。如果 `onFinally` 不是函数，则调用 `then()` 时使用 `onFinally` 同时作为两个参数——对于 `Promise.prototype.then()`，这意味着没有附加有效的处理器。否则，`then()` 被调用时会使用两个内部创建的函数，其行为如下：

**警告：** 这只是为了演示，而不是一个 polyfill。

```js
promise.then(
  (value) => Promise.resolve(onFinally()).then(() => value),
  (reason) =>
    Promise.resolve(onFinally()).then(() => {
      throw reason;
    }),
);
```

因为 `finally()` 调用 `then()`，所以它支持子类化。此外，请注意上面的 `Promise.resolve()` 调用——实际上，`onFinally()` 的返回值是使用与 `Promise.resolve()` 相同的算法解决的，但用于构造解决的 promise 的实际构造函数将是子类。`finally()` 通过 `promise.constructor[@@species]` 获取构造函数。

示例
--

### 使用 finally()

```js
let isLoading = true;

fetch(myRequest)
  .then((response) => {
    const contentType = response.headers.get("content-type");
    if (contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then((json) => {
    /\* 进一步处理 JSON \*/
  })
  .catch((error) => {
    console.error(error); // 这行代码也可能抛出错误，例如：when console = {}
  })
  .finally(() => {
    isLoading = false;
  });
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.finally |

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

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

参见
--

* `core-js` 中 `Promise.prototype.finally` 的 Polyfill
* `Promise`
* `Promise.prototype.then()`
* `Promise.prototype.catch()`


Promise.any() - JavaScript

Promise.any()
=============

**`Promise.any()`** 静态方法将一个 Promise 可迭代对象作为输入，并返回一个 `Promise`。当输入的任何一个 Promise 兑现时，这个返回的 Promise 将会兑现，并返回第一个兑现的值。当所有输入 Promise 都被拒绝（包括传递了空的可迭代对象）时，它会以一个包含拒绝原因数组的 `AggregateError` 拒绝。

尝试一下
----

语法
--

```js
Promise.any(iterable)
```

### 参数

`iterable`

一个 promise 的可迭代对象（例如一个数组）。

### 返回值

一个 `Promise`，其状态为：

* **已拒绝（already rejected）**，如果传入的 `iterable` 为空的话。
* **异步兑现（asynchronously fulfilled）**，当给定的 `iterable` 中的任何一个 Promise 被兑现时，返回的 Promise 就会被兑现。其兑现值是第一个兑现的 Promise 的兑现值。
* **异步拒绝（asynchronously rejected）**，当给定的 `iterable` 中的所有 Promise 都被拒绝时。拒绝原因是一个 `AggregateError`，其 `errors` 属性包含一个拒绝原因数组。无论完成顺序如何，这些错误都是按照传入的 Promise 的顺序排序。如果传递的 `iterable` 是非空的，但不包含待定的 Promise，则返回的 Promise 仍然是异步拒绝的（而不是同步拒绝的）。
描述
--

`Promise.any()` 方法是 Promise 并发方法之一。该方法对于返回第一个兑现的 Promise 非常有用。一旦有一个 Promise 兑现，它就会立即返回，因此不会等待其他 Promise 完成。

与 `Promise.all()` 返回一个兑现值*数组*不同的是，我们只会得到一个兑现值（假设至少有一个 Promise 被兑现）。此方法对于那些如果我们只需要一个 Promise 被兑现，但不在意哪一个被兑现的情况更有益。请注意另一个区别：该方法在接收到*空的可迭代对象*时会拒绝，因为实际上，该可迭代对象不包含任何兑现的项。你可以将 `Promise.any()` 和 `Promise.all()` 与 `Array.prototype.some()` 和 `Array.prototype.every()` 进行比较。

同时，与 `Promise.race()` 返回第一个*敲定*（无论是兑现还是拒绝）的值不同的是，该方法返回第一个*兑现*的值。该方法忽略所有被拒绝的 Promise，直到第一个被兑现的 Promise。

示例
--

### 使用 Promise.any()

`Promise.any()` 会以第一个兑现的 Promise 来兑现，即使有 Promise 先被拒绝。这与 `Promise.race()` 不同，后者会使用第一个敲定的 Promise 来兑现或拒绝。

```js
const pErr = new Promise((resolve, reject) => {
  reject("总是失败");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "最终完成");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "很快完成");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log(value);
  // pFast 第一个兑现
});
// 打印：
// 很快完成
```

### 拒绝并返回 AggregateError

如果没有 Promise 被兑现，`Promise.any()` 将使用 `AggregateError` 进行拒绝。

```js
const failure = new Promise((resolve, reject) => {
  reject("总是失败");
});

Promise.any([failure]).catch((err) => {
  console.log(err);
});
// AggregateError: No Promise in Promise.any was resolved
```

### 显示第一张已加载的图片

在这个例子，我们有一个获取图片并返回 blob 的函数，我们使用 `Promise.any()` 来获取一些图片并显示第一张可用的图片（即最先解决的那个 promise）。

```js
async function fetchAndDecode(url, description) {
  const res = await fetch(url);
  if (!res.ok) {
    throw new Error(`HTTP 错误！状态码：${res.status}`);
  }
  const data = await res.blob();
  return [data, description];
}

const coffee = fetchAndDecode("coffee.jpg", "Coffee");
const tea = fetchAndDecode("tea.jpg", "Tea");

Promise.any([coffee, tea])
  .then(([blob, description]) => {
    const objectURL = URL.createObjectURL(blob);
    const image = document.createElement("img");
    image.src = objectURL;
    image.alt = description;
    document.body.appendChild(image);
  })
  .catch((e) => {
    console.error(e);
  });
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.any |

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

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

参见
--

* `core-js` 中 `Promise.any` 的 polyfill
* `Promise`
* `Promise.all()`
* `Promise.allSettled()`
* `Promise.race()`


Promise.resolve() - JavaScript

Promise.resolve()
=================

**`Promise.resolve()`** 静态方法将给定的值转换为一个 `Promise`。如果该值本身就是一个 Promise，那么该 Promise 将被返回；如果该值是一个 thenable 对象，`Promise.resolve()` 将调用其 `then()` 方法及其两个回调函数；否则，返回的 Promise 将会以该值兑现。

该函数将嵌套的类 Promise 对象（例如，一个将被兑现为另一个 Promise 对象的 Promise 对象）展平，转化为单个 Promise 对象，其兑现值为一个非 thenable 值。

尝试一下
----

语法
--

```js
Promise.resolve(value)
```

### 参数

`value`

要被该 `Promise` 对象解决的参数。也可以是一个 `Promise` 对象或一个 thenable 对象。

### 返回值

一个由给定值解决的 `Promise`，或者如果该值为一个 Promise 对象，则返回该对象。用于解决的 Promise 可以处于已兑现、已拒绝或待定状态中的任何一种。例如，对一个已拒绝的 Promise 进行调用仍将返回一个已拒绝的 Promise。

描述
--

`Promise.resolve()` 方法用于*解决*（resolve）一个 Promise 对象，但这与“兑现”（fulfill）或“拒绝”（reject）Promise 对象并不相同。有关术语的定义，请参见 Promise 描述。简而言之，`Promise.resolve()` 返回一个 Promise 对象，其最终状态取决于另一个 Promise 对象、thenable 对象或其他值。

`Promise.resolve()` 方法是一个通用方法，支持子类化，这意味着它可以在 `Promise` 的子类上调用，并且结果会是该子类类型的 Promise 对象。为此，子类的构造函数必须实现与 `Promise()` 构造函数相同的签名，即接受一个 `executor` 函数，该函数可以用 `resolve` 和 `reject` 回调函数作为参数进行调用。

`Promise.resolve()` 方法特殊处理了原生 `Promise` 实例。如果 `value` 属于 `Promise` 或其子类，并且 `value.constructor === Promise`，那么 `Promise.resolve()` 直接返回 `value`，而不会创建一个新的 `Promise` 实例。否则，`Promise.resolve()` 实际上相当于 `new Promise((resolve) => resolve(value))` 的简写形式。

实际上，大部分解决逻辑是由 `Promise()` 构造函数传递的 resolver 函数实现的，简单概括如下：

* 如果传入的是一个非 thenable 对象的值，则返回的 Promise 对象将以该值兑现。
* 如果传入的是一个 thenable 对象，则通过传入一对解决函数作为参数调用该 thenable 对象的 `then` 方法后得到的状态将作为返回的 Promise 对象的状态。（但是因为原生的 Promise 直接通过 `Promise.resolve()` 调用，而不创建封装对象，所以不会在原生 Promise 上调用 `then` 方法。）如果 resolver 函数接收到另一个 thenable 对象，则会再次进行解决，以确保 Promise 对象的最终兑现值永远不会是 thenable 对象。
示例
--

### 使用 Promise.resolve 静态方法

```js
Promise.resolve("成功").then(
  (value) => {
    console.log(value); // "成功"
  },
  (reason) => {
    // 不会被调用
  },
);
```

### resolve 一个数组

```js
const p = Promise.resolve([1, 2, 3]);
p.then((v) => {
  console.log(v[0]); // 1
});
```

### resolve 另一个 promise

`Promise.resolve()` 方法会重用已存在的 `Promise` 实例。如果它正在解决一个原生的 Promise，它将返回同一 Promise 实例，而不会创建一个封装对象。

```js
const original = Promise.resolve(33);
const cast = Promise.resolve(original);
cast.then((value) => {
  console.log(`值：${value}`);
});
console.log(`original === cast ? ${original === cast}`);

// 按顺序打印：
// original === cast ? true
// 值：33
```

日志输出顺序颠倒其实是由于异步地调用 `then` 处理器。请参见 `then()` 参考文档获取更多信息。

### resolve thenable 对象并抛出错误

```js
// Resolve 一个 thenable 对象
const p1 = Promise.resolve({
  then(onFulfill, onReject) {
    onFulfill("已兑现！");
  },
});
console.log(p1 instanceof Promise); // true，thenable 对象被转换为一个 Promise 对象

p1.then(
  (v) => {
    console.log(v); // "已兑现！"
  },
  (e) => {
    // 不会被调用
  },
);

// Thenable 在回调之前抛出异常
// Promise 被拒绝
const thenable = {
  then(onFulfilled) {
    throw new TypeError("抛出异常");
    onFulfilled("Resolving");
  },
};

const p2 = Promise.resolve(thenable);
p2.then(
  (v) => {
    // 不会被调用
  },
  (e) => {
    console.error(e); // TypeError: 抛出异常
  },
);

// Thenable 在回调 Promise 被解决之后抛出异常
const thenable = {
  then(onFulfilled) {
    onFulfilled("解决");
    throw new TypeError("Throwing");
  },
};

const p3 = Promise.resolve(thenable);
p3.then(
  (v) => {
    console.log(v); // "解决"
  },
  (e) => {
    // 不会被调用
  },
);
```

嵌套的 thenable 对象将被“深度展平”为单个 Promise 对象。

```js
const thenable = {
  then(onFulfilled, onRejected) {
    onFulfilled({
      // 该 thenable 对象将兑现为另一个 thenable 对象
      then(onFulfilled, onRejected) {
        onFulfilled(42);
      },
    });
  },
};

Promise.resolve(thenable).then((v) => {
  console.log(v); // 42
});
```

**警告：** 不要在一个解决为自身的 thenable 对象上调用 `Promise.resolve()`。这将导致无限递归，因为它试图展平一个无限嵌套的 Promise。

```js
const thenable = {
  then(onFulfilled, onRejected) {
    onFulfilled(thenable);
  },
};

Promise.resolve(thenable); // 将会导致无限递归。
```

### 在非 Promise 构造函数上调用 resolve()

`Promise.resolve()` 是一个通用方法。它可以在任何实现与 `Promise()` 构造函数相同签名的构造函数上调用。例如，我们可以在一个构造函数上调用它，并将 `console.log` 作为 `resolve` 参数传递：

```js
class NotPromise {
  constructor(executor) {
    // “resolve”和“reject”函数的行为与原生 Promise 完全不同，但 `Promise.resolve()` 方法以相同的方式调用它们。
    executor(
      (value) => console.log("已解决", value),
      (reason) => console.log("已拒绝", reason),
    );
  }
}

Promise.resolve.call(NotPromise, "foo"); // 输出 "已解决 foo"
```

展平嵌套的 thenable 对象的能力是由 `Promise()` 构造函数的 resolver 函数实现的，因此如果你在另一个构造函数上调用它，嵌套的 thenable 对象可能不会被展平，这取决于该构造函数如何实现其 resolver 函数。

```js
const thenable = {
  then(onFulfilled, onRejected) {
    onFulfilled({
      // 该 thenable 对象将兑现为另一个 thenable 对象
      then(onFulfilled, onRejected) {
        onFulfilled(42);
      },
    });
  },
};

Promise.resolve.call(NotPromise, thenable); // 输出 "已兑现 { then: [Function: then] }"
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.resolve |

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

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

参见
--

* `Promise`


Promise.prototype.then() - JavaScript

Promise.prototype.then()
========================

`Promise` 实例的 **`then()`** 方法最多接受两个参数：用于 `Promise` 兑现和拒绝情况的回调函数。它立即返回一个等效的 `Promise` 对象，允许你链接到其他 Promise 方法，从而实现链式调用。

尝试一下
----

语法
--

```js
then(onFulfilled)
then(onFulfilled, onRejected)
```

### 参数

`onFulfilled` 可选

一个在此 Promise 对象被兑现时异步执行的函数。它的返回值将成为 `then()` 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数：

`value`

Promise 对象的兑现值。

如果 `onFulfilled` 不是一个函数，则内部会被替换为一个*恒等*函数（`(x) => x`），它只是简单地将兑现值向前传递。

`onRejected` 可选

一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 `catch()` 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数：

`reason`

Promise 对象被拒绝的原因。

如果 `onRejected` 不是一个函数，则内部会被替换为一个*抛出器*函数（`(x) => { throw x; }`），它会抛出它收到的拒绝原因。

### 返回值

立即返回一个新的 `Promise` 对象，该对象始终处于待定状态，无论当前 Promise 对象的状态如何。

`onFulfilled` 和 `onRejected` 处理函数之一将被执行，以处理当前 Promise 对象的兑现或拒绝。即使当前 Promise 对象已经敲定，这个调用也总是异步发生的。返回的 Promise 对象（称之为 `p`）的行为取决于处理函数的执行结果，遵循一组特定的规则。如果处理函数：

* 返回一个值：`p` 以该返回值作为其兑现值。
* 没有返回任何值：`p` 以 `undefined` 作为其兑现值。
* 抛出一个错误：`p` 抛出的错误作为其拒绝值。
* 返回一个已兑现的 Promise 对象：`p` 以该 Promise 的值作为其兑现值。
* 返回一个已拒绝的 Promise 对象：`p` 以该 Promise 的值作为其拒绝值。
* 返回另一个待定的 Promise 对象：`p` 保持待定状态，并在该 Promise 对象被兑现/拒绝后立即以该 Promise 的值作为其兑现/拒绝值。
描述
--

`then()` 方法用于为 Promise 对象的完成（兑现或拒绝）设置回调函数。它是 Promise 的基本方法：thenable 协议要求所有类 Promise 对象都提供一个 `then()` 方法，并且 `catch()` 和 `finally()` 方法都会通过调用该对象的 `then()` 方法来工作。

有关 `onRejected` 处理函数的更多信息，请参阅 `catch()` 参考文档。

`then()` 方法返回一个新的 Promise 对象。如果在同一 Promise 对象上两次调用 `then()` 方法（而不是链式调用），则该 Promise 对象将具有两对处理方法。附加到同一 Promise 对象的所有处理方法总是按照它们添加的顺序调用。此外，每次调用 `then()` 方法返回的两个 Promise 对象开始了独立的链，不会等待彼此的敲定。

沿着 `then()` 链产生的 thenable 对象总是会被解决——`onFulfilled` 处理函数永远不会收到 thenable 对象，并且任何由处理函数返回的 thenable 对象在传递给下一个处理函数之前总是被解决。这是因为在构造新的 Promise 对象时，由 `executor` 传递的 `resolve` 和 `reject` 函数被保存下来，在当前 Promise 对象敲定时，相应的函数将被调用，并传递兑现值或拒绝原因。解决逻辑来自 `Promise()` 构造函数传递的解决函数。

`then()` 方法支持子类化，这意味着它可以在 `Promise` 子类的实例上调用，并且结果将是子类类型的 Promise 对象。你可以通过 `@@species` 属性自定义返回值类型。

示例
--

### 使用 then() 方法

```js
const p1 = new Promise((resolve, reject) => {
  resolve("成功！");
  // 或
  // reject(new Error("错误!"));
});

p1.then(
  (value) => {
    console.log(value); // 成功！
  },
  (reason) => {
    console.error(reason); // 错误！
  },
);
```

### 传入非函数作为参数

```js
Promise.resolve(1).then(2).then(console.log); // 1
Promise.reject(1).then(2, 2).then(console.log, console.log); // 1
```

### 链式调用

`then` 方法返回一个新的 `Promise`，从而允许链式调用。

如果作为 `then()` 方法的处理函数传递的函数返回一个 `Promise`，则相应的 `Promise` 对象将被暴露给方法链中的后续 `then()` 方法。下面的代码段使用 `setTimeout` 函数来模拟异步代码操作。

```js
Promise.resolve("foo")
  // 1. 接收 "foo" 并与 "bar" 拼接，并将其结果做为下一个 resolve 返回。
  .then(
    (string) =>
      new Promise((resolve, reject) => {
        setTimeout(() => {
          string += "bar";
          resolve(string);
        }, 1);
      }),
  )
  // 2. 接收 "foobar", 放入一个异步函数中处理该字符串
  // 并将其打印到控制台中，但是不将处理后的字符串返回到下一个。
  .then((string) => {
    setTimeout(() => {
      string += "baz";
      console.log(string); // foobarbaz
    }, 1);
    return string;
  })
  // 3. 打印本节中代码将如何运行的帮助消息，
  // 字符串实际上是由上一个回调函数之前的那块异步代码处理的。
  .then((string) => {
    console.log(
      "最后一个 then：哎呀……之前懒得实例化并返回一个 Promise，所以顺序可能有点令人惊讶",
    );

    // 注意 `string` 这时不会存在 'baz'。
    // 因为这是发生在我们通过 setTimeout 模拟的异步函数中。
    console.log(string); // foobar
  });

// 按顺序打印：
// 最后一个 then：哎呀……之前懒得实例化并返回一个 Promise，所以顺序可能有点令人惊讶
// foobar
// foobarbaz
```

`then()` 方法返回的值的解决方式与 `Promise.resolve()` 相同。这意味着该方法支持 thenable 对象，如果返回值不是一个 Promise 对象，则会隐式地将其包装在 `Promise` 中，然后解决。

```js
const p2 = new Promise((resolve, reject) => {
  resolve(1);
});

p2.then((value) => {
  console.log(value); // 1
  return value + 1;
}).then((value) => {
  console.log(value, "- A synchronous value works"); // 2 - A synchronous value works
});

p2.then((value) => {
  console.log(value); // 1
});
```

如果函数抛出错误或返回一个被拒绝的 Promise，则 `then` 返回的 Promise 最终将被拒绝。

```js
Promise.resolve()
  .then(() => {
    // 令 .then() 返回一个被拒绝的 promise
    throw new Error("Oh no!");
  })
  .then(
    () => {
      console.log("不会被调用。");
    },
    (error) => {
      console.error(`onRejected 函数被调用：${error.message}`);
    },
  );
```

在实践中，通常更希望使用 `catch()` 方法来捕获被拒绝的 Promise，而不是使用 `then()` 方法传入两个处理器的语法，如下例所示。

```js
Promise.resolve()
  .then(() => {
    // 令 .then() 返回一个被拒绝的 promise
    throw new Error("噢，不！");
  })
  .catch((error) => {
    console.error(`onRejected 函数被调用：${error.message}`);
  })
  .then(() => {
    console.log("即使前面的 Promise 被拒绝，我也总是会被调用");
  });
```

在其他所有情况下，返回的 Promise 最终都会被兑现。在下面的示例中，即使链中的前一个 Promise 被拒绝，第一个 `then()` 返回一个包装着 `42` 的已兑现的 Promise。

```js
Promise.reject()
  .then(
    () => 99,
    () => 42,
  ) // onRejected 返回 42，它被封装在已兑现的 Promise 中
  .then((solution) => console.log(`兑现为：${solution}`)); // 兑现为：42
```

如果 `onFulfilled` 返回一个 Promise，那么 `then` 的返回值将根据该 Promise 的最终状态被兑现或被拒绝。

```js
function resolveLater(resolve, reject) {
  setTimeout(() => {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(() => {
    reject(new Error("错误"));
  }, 1000);
}

const p1 = Promise.resolve("foo");
const p2 = p1.then(() => {
  // 此处返回一个 Promise，将在 1 秒后解决为 10
  return new Promise(resolveLater);
});
p2.then(
  (v) => {
    console.log("已解决", v); // "已解决", 10
  },
  (e) => {
    // 不会被调用
    console.error("已拒绝", e);
  },
);

const p3 = p1.then(() => {
  // 此处返回一个 Promise，将在 1 秒后以 '错误' 被拒绝
  return new Promise(rejectLater);
});
p3.then(
  (v) => {
    // 不会被调用
    console.log("已解决", v);
  },
  (e) => {
    console.error("已拒绝", e); // "已拒绝", '错误'
  },
);
```

你可以使用链式调用，在一个函数上实现基于 Promise 的 API，在另一个函数之上。

```js
function fetchCurrentData() {
  // fetch() API 返回一个 Promise。
  // 这个函数提供了一个类似的 API，但是它对 Promise 的兑现值进行了更多处理
  return fetch("current-data.json").then((response) => {
    if (response.headers.get("content-type") !== "application/json") {
      throw new TypeError();
    }
    const j = response.json();
    // 可以对 j 进行一些处理

    // 兑现值将会传递给 fetchCurrentData().then() 中的处理函数
    return j;
  });
}
```

### then() 的异步性

以下是一个示例，用于演示 `then` 方法的异步性。

```js
// 用一个已解决的 Promise——“resolvedProm”为例，
// 函数调用“resolvedProm.then(...)”立即返回一个新的 Promise，
// 但是其中的处理器“(value) => {...}”将被异步调用，正如打印输出所示。
// 新的 Promise 被赋值给“thenProm”，
// 并且 thenProm 将被解决为处理函数返回的值。
const resolvedProm = Promise.resolve(33);
console.log(resolvedProm);

const thenProm = resolvedProm.then((value) => {
  console.log(
    `在主堆栈结束后被调用。收到的值是：${value}，返回的值是：${value + 1}`,
  );
  return value + 1;
});
console.log(thenProm);

// 使用 setTimeout，我们可以将函数的执行推迟到调用栈为空的时刻。
setTimeout(() => {
  console.log(thenProm);
});

// 按顺序打印：
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 33}
// Promise {[[PromiseStatus]]: "pending", [[PromiseResult]]: undefined}
// "在主堆栈结束后被调用。收到的值是：33，返回的值是：34"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 34}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.then |

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

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

参见
--

* `Promise`
* `Promise.prototype.catch()`


Promise.all() - JavaScript

Promise.all()
=============

**`Promise.all()`** 静态方法接受一个 Promise 可迭代对象作为输入，并返回一个 `Promise`。当所有输入的 Promise 都被兑现时，返回的 Promise 也将被兑现（即使传入的是一个空的可迭代对象），并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝，则返回的 Promise 将被拒绝，并带有第一个被拒绝的原因。

尝试一下
----

语法
--

```js
Promise.all(iterable)
```

### 参数

`iterable`

一个可迭代对象，例如 `Array` 或 `String`。

### 返回值

一个 `Promise`，其状态为：

* **已兑现（already fulfilled）**，如果传入的 `iterable` 为空。
* **异步兑现（asynchronously fulfilled）**，如果给定的 `iterable` 中所有的 promise 都已兑现。兑现值是一个数组，其元素顺序与传入的 promise 一致，而非按照兑现的时间顺序排列。如果传入的 `iterable` 是一个非空但不包含待定的（pending）promise，则返回的 promise 依然是异步兑现，而非同步兑现。
* **异步拒绝（asynchronously rejected）**，如果给定的 `iterable` 中的任意 promise 被拒绝。拒绝原因是第一个拒绝的 promise 的拒绝原因。
描述
--

`Promise.all()` 方法是 promise 并发方法之一。它可用于聚合多个 Promise 的结果。通常在有多个相关的异步任务并且整个代码依赖于这些任务成功完成时使用，我们希望在代码执行继续之前完成所有任务。

`Promise.all()` 方法会在**任何一个**输入的 Promise 被拒绝时立即拒绝。相比之下，`Promise.allSettled()` 方法返回的 Promise 会等待所有输入的 Promise 完成，不管其中是否有 Promise 被拒绝。如果你需要获取输入可迭代对象中每个 Promise 的最终结果，则应使用 `allSettled()` 方法。

示例
--

### 使用 Promise.all()

`Promise.all` 等待所有兑现（或第一个拒绝）的结果。

```js
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 100);
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [3, 1337, "foo"]
});
```

如果 `iterable` 包含非 promise 值，这些值将被忽略，但仍包含在返回的 promise 数组值中（如果该 promise 得到了兑现）：

```js
// 所有的值都不是 Promise，因此返回的 Promise 将被兑现
const p = Promise.all([1, 2, 3]);
// 输入中唯一的 Promise 已经被兑现，因此返回的 Promise 将被兑现
const p2 = Promise.all([1, 2, 3, Promise.resolve(444)]);
// 一个（也是唯一的一个）输入 Promise 被拒绝，因此返回的 Promise 将被拒绝
const p3 = Promise.all([1, 2, 3, Promise.reject(555)]);

// 使用 setTimeout，我们可以在队列为空后执行代码
setTimeout(() => {
  console.log(p);
  console.log(p2);
  console.log(p3);
});

// 打印：
// Promise { <state>: "fulfilled", <value>: Array[3] }
// Promise { <state>: "fulfilled", <value>: Array[4] }
// Promise { <state>: "rejected", <reason>: 555 }
```

### Promise.all 的异步性和同步性

以下示例演示了在传递非空的 `iterable` 时 `Promise.all` 的异步性：

```js
// 传入一个已经 resolved 的 Promise 数组，以尽可能快地触发 Promise.all
const resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

const p = Promise.all(resolvedPromisesArray);
// 立即打印 p 的值
console.log(p);

// 使用 setTimeout，我们可以在队列为空后执行代码
setTimeout(() => {
  console.log("队列现在为空");
  console.log(p);
});

// 按顺序打印：
// Promise { <state>: "pending" }
// 队列现在为空
// Promise { <state>: "fulfilled", <value>: Array[2] }
```

如果 `Promise.all` 失败，也是一样的：

```js
const mixedPromisesArray = [Promise.resolve(33), Promise.reject(44)];
const p = Promise.all(mixedPromisesArray);
console.log(p);
setTimeout(() => {
  console.log("队列现在为空");
  console.log(p);
});

// Logs:
// Promise { <state>: "pending" }
// 队列现在为空
// Promise { <state>: "rejected", <reason>: 44 }
```

只有当传递给 `Promise.all` 的 `iterable` 为空时，`Promise.all` 才会同步解决。

```js
const p = Promise.all([]); // 将会立即解决
const p2 = Promise.all([1337, "hi"]); // 非 promise 值将被忽略，但求值是异步进行的
console.log(p);
console.log(p2);
setTimeout(() => {
  console.log("队列现在为空");
  console.log(p2);
});

// Logs:
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// 队列现在为空
// Promise { <state>: "fulfilled", <value>: Array[2] }
```

### 将 Promise.all() 与异步函数一起使用

在 async 函数中，“过度 await”代码非常普遍。例如，给定以下函数：

```js
function promptForDishChoice() {
  return new Promise((resolve, reject) => {
    const dialog = document.createElement("dialog");
    dialog.innerHTML = `
<form method="dialog">
 <p>What would you like to eat?</p>
 <select>
 <option value="pizza">Pizza</option>
 <option value="pasta">Pasta</option>
 <option value="salad">Salad</option>
 </select>
 <menu>
 <li><button value="cancel">Cancel</button></li>
 <li><button type="submit" value="ok">OK</button></li>
 </menu>
</form>
 `;
    dialog.addEventListener("close", () => {
      if (dialog.returnValue === "ok") {
        resolve(dialog.querySelector("select").value);
      } else {
        reject(new Error("User cancelled dialog"));
      }
    });
    document.body.appendChild(dialog);
    dialog.showModal();
  });
}

async function fetchPrices() {
  const response = await fetch("/prices");
  return await response.json();
}
```

你可能会写一个像下面这样的函数：

```js
async function getPrice() {
  const choice = await promptForDishChoice();
  const prices = await fetchPrices();
  return prices[choice];
}
```

然而，请注意，`promptForDishChoice` 和 `fetchPrices` 的执行不依赖于彼此的结果。当用户选择他们的菜肴时，可以在后台获取价格，但是在上面的代码中，`await` 运算符会导致异步函数暂停，直到选择完成，然后再次暂停，直到获取到价格。我们可以使用 `Promise.all` 并发地运行它们，以便用户在结果给出之前不必等待获取价格：

```js
async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice(),
    fetchPrices(),
  ]);
  return prices[choice];
}
```

`Promise.all` 在这里是并发方法中的最佳选择，因为错误处理很直观——如果有任何一个 Promise 被拒绝，结果将不再可用，整个 `await` 表达式会抛出异常。

`Promise.all` 接受一个 Promise 可迭代对象，因此如果要使用它来并行执行多个异步函数，你需要调用这些异步函数并使用返回的 Promise。直接将函数传递给 `Promise.all` 是不起作用的，因为它们不是 Promise。

```js
async function getPrice() {
  const [choice, prices] = await Promise.all([
    promptForDishChoice,
    fetchPrices,
  ]);
  // `choice` 和 `prices` 仍然是原始的异步函数；
  // Promise.all() 对非 Promise 不起作用
}
```

### Promise.all 的快速失败行为

`Promise.all` 在任意一个传入的 promise 失败时返回失败。例如，如果你传入四个超时后解决的 promise 和一个立即拒绝的 promise，那么 `Promise.all` 将立即被拒绝。

```js
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("一"), 1000);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("二"), 2000);
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("三"), 3000);
});
const p4 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("四"), 4000);
});
const p5 = new Promise((resolve, reject) => {
  reject(new Error("拒绝"));
});

// 使用 .catch:
Promise.all([p1, p2, p3, p4, p5])
  .then((values) => {
    console.log(values);
  })
  .catch((error) => {
    console.error(error.message);
  });

// 打印：
// "拒绝"
```

通过处理可能的拒绝，可以更改此行为：

```js
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("p1 延迟解决"), 1000);
});

const p2 = new Promise((resolve, reject) => {
  reject(new Error("p2 立即拒绝"));
});

Promise.all([p1.catch((error) => error), p2.catch((error) => error)]).then(
  (values) => {
    console.log(values[0]); // "p1 延迟解决"
    console.error(values[1]); // "Error: p2 立即拒绝"
  },
);
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.all |

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

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

参见
--

* `Promise`
* `Promise.allSettled()`
* `Promise.any()`
* `Promise.race()`


Promise.race() - JavaScript

Promise.race()
==============

**`Promise.race()`** 静态方法接受一个 promise 可迭代对象作为输入，并返回一个 `Promise`。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

尝试一下
----

语法
--

```js
Promise.race(iterable)
```

### 参数

`iterable`

一个 promise 可迭代对象（例如数组）。

### 返回值

一个 `Promise`，会以 `iterable` 中第一个敲定的 promise 的状态**异步敲定**。换句话说，如果第一个敲定的 promise 被兑现，那么返回的 promise 也会被兑现；如果第一个敲定的 promise 被拒绝，那么返回的 promise 也会被拒绝。如果传入的 `iterable` 为空，返回的 promise 就会一直保持待定状态。如果传入的 `iterable` 非空但其中没有任何一个 promise 是待定状态，返回的 promise 仍会异步敲定（而不是同步敲定）。

描述
--

`Promise.race()` 方法是 Promise 并发方法之一。当你想要第一个异步任务完成时，但不关心它的最终状态（即它既可以成功也可以失败）时，它就非常有用。

如果可迭代对象中包含一个或多个非 promise 值和/或已敲定的 promise，则 `Promise.race()` 将以可迭代对象中找到的第一个此类值敲定。

示例
--

### 使用 Promise.race()

这个例子展示了如何使用 `Promise.race()` 来比较多个使用 `setTimeout()` 实现的计时器。计时时间最短的计时器总是赢得竞态，并成为返回的 promise 状态。

```js
function sleep(time, value, state) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (state === "兑现") {
        return resolve(value);
      } else {
        return reject(new Error(value));
      }
    }, time);
  });
}

const p1 = sleep(500, "一", "兑现");
const p2 = sleep(100, "二", "兑现");

Promise.race([p1, p2]).then((value) => {
  console.log(value); // “二”
  // 两个都会兑现，但 p2 更快
});

const p3 = sleep(100, "三", "兑现");
const p4 = sleep(500, "四", "拒绝");

Promise.race([p3, p4]).then(
  (value) => {
    console.log(value); // “三”
    // p3 更快，所以它兑现
  },
  (error) => {
    // 不会被调用
  },
);

const p5 = sleep(500, "五", "兑现");
const p6 = sleep(100, "六", "拒绝");

Promise.race([p5, p6]).then(
  (value) => {
    // 不会被调用
  },
  (error) => {
    console.error(error.message); // “六”
    // p6 更快，所以它拒绝
  },
);
```

### Promise.race 的异步性

以下示例演示了 `Promise.race` 的异步性。与其他 promise 并发方法不同，`Promise.race` 总是异步的：即使 `iterable` 为空，它也永远不会同步地完成。

```js
// 传入一个已经解决的 Promise 数组，以尽快触发 Promise.race。
const resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

const p = Promise.race(resolvedPromisesArray);
// 立即打印 p 的值
console.log(p);

// 使用 setTimeout，我们可以在堆栈为空后执行代码
setTimeout(() => {
  console.log("堆栈现在为空");
  console.log(p);
});

// 按顺序打印：
// Promise { <state>: "pending" }
// 堆栈现在为空
// Promise { <state>: "fulfilled", <value>: 33 }
```

一个空的可迭代对象会导致返回的 Promise 一直处于待定状态：

```js
const foreverPendingPromise = Promise.race([]);
console.log(foreverPendingPromise);
setTimeout(() => {
  console.log("堆栈现在为空");
  console.log(foreverPendingPromise);
});

// 按顺序打印：
// Promise { <state>: "pending" }
// 堆栈现在为空
// Promise { <state>: "pending" }
```

如果可迭代对象包含一个或多个非 Promise 值和/或一个已经敲定的 Promise，则 `Promise.race` 会以数组中找到的第一个这样的值敲定：

```js
const foreverPendingPromise = Promise.race([]);
const alreadyFulfilledProm = Promise.resolve(100);

const arr = [foreverPendingPromise, alreadyFulfilledProm, "非 Promise 值"];
const arr2 = [foreverPendingPromise, "非 Promise 值", Promise.resolve(100)];
const p = Promise.race(arr);
const p2 = Promise.race(arr2);

console.log(p);
console.log(p2);
setTimeout(() => {
  console.log("堆栈现在为空");
  console.log(p);
  console.log(p2);
});

// 按顺序打印：
// Promise { <state>: "pending" }
// Promise { <state>: "pending" }
// 堆栈现在为空
// Promise { <state>: "fulfilled", <value>: 100 }
// Promise { <state>: "fulfilled", <value>: "非 Promise 值" }
```

### 使用 Promise.race() 实现请求超时

你可以使用一个定时器来与一个可能持续很长时间的请求进行竞争，以便超出时间限制时，返回的 Promise 自动拒绝。

```js
const data = Promise.race([
  fetch("/api"),
  new Promise((resolve, reject) => {
    // 5 秒后拒绝
    setTimeout(() => reject(new Error("请求超时")), 5000);
  }),
])
  .then((res) => res.json())
  .catch((err) => displayError(err));
```

如果 `data` Promise 被兑现，它将包含从 `/api` 获取的数据；否则，如果 `fetch` 保持待定状态并输给 `setTimeout` 定时器，这个 Promise 将在 5 秒后被拒绝。

### 使用 Promise.race() 检测 Promise 的状态

由于 `Promise.race()` 解决的可迭代对象中第一个非待定状态的 Promise，我们可以检查一个 Promise 的状态，包括它是否处于待定状态。这个示例是从 `promise-status-async` 改编而来的。

```js
function promiseState(promise) {
  const pendingState = { status: "待定" };

  return Promise.race([promise, pendingState]).then(
    (value) => (value === pendingState ? value : { status: "已兑现", value }),
    (reason) => ({ status: "已拒绝", reason }),
  );
}
```

在这个函数中，如果 `promise` 是待定状态，非 Promise 类型的第二个值 `pendingState` 将成为这个 `race` 的结果；否则，如果 `promise` 已经敲定，我们可以通过 `onFulfilled` 和 `onRejected` 处理函数来知道它的状态。例如：

```js
const p1 = new Promise((res) => setTimeout(() => res(100), 100));
const p2 = new Promise((res) => setTimeout(() => res(200), 200));
const p3 = new Promise((res, rej) => setTimeout(() => rej(300), 100));

async function getStates() {
  console.log(await promiseState(p1));
  console.log(await promiseState(p2));
  console.log(await promiseState(p3));
}

console.log("开始状态：");
getStates();
setTimeout(() => {
  console.log("等待 100ms 后：");
  getStates();
}, 100);

// 打印：
// 开始状态：
// { status: '待定' }
// { status: '待定' }
// { status: '待定' }
// 等待 100ms 后：
// { status: '已兑现', value: 100 }
// { status: '待定' }
// { status: '已拒绝', reason: 300 }
```

**备注：** `promiseState` 函数仍然是异步执行的，因为没有办法同步地获取 Promise 的值（即不使用 `then()` 或 `await`），即使它已经敲定。但是，`promiseState()` 总是在一次事件循环内就会完成，并且实际上从不等待任何 Promise 的敲定。

### 与 Promise.any() 的比较

`Promise.race` 方法以可迭代对象中第一个敲定的 `Promise` 作为敲定值。

```js
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "一");
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "二");
});

Promise.race([promise1, promise2])
  .then((value) => {
    console.log("成功，值为：", value);
  })
  .catch((reason) => {
    // 只有 promise1 成功兑现，但 promise2 更快
    console.error("失败，原因为：", reason);
  });
// 失败，原因为：二
```

`Promise.any` 方法以可迭代对象中第一个被兑现的 `Promise` 作为兑现值。

```js
const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "一");
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 100, "二");
});

Promise.any([promise1, promise2])
  .then((value) => {
    // 只有 promise1 成功兑现，即使 promise2 更快敲定
    console.log("成功，值为：", value);
  })
  .catch((reason) => {
    console.error("失败，原因为：", reason);
  });
// 成功，值为：一
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.race |

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

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

参见
--

* `Promise`
* `Promise.all()`
* `Promise.allSettled()`
* `Promise.any()`


Promise.reject() - JavaScript

Promise.reject()
================

**`Promise.reject()`** 静态方法返回一个已拒绝（rejected）的 `Promise` 对象，拒绝原因为给定的参数。

尝试一下
----

语法
--

```js
Promise.reject(reason)
```

### 参数

`reason`

该 `Promise` 对象被拒绝的原因。

### 返回值

返回一个已拒绝（rejected）的 `Promise`，拒绝原因为给定的参数。

描述
--

`Promise.reject` 静态方法返回一个被拒绝的 `Promise` 对象。通过使用 `Error` 的实例获取错误原因 `reason` 对调试和选择性错误捕捉很有帮助。

`Promise.reject()` 方法是一个通用方法，支持子类化，这意味着它可以在 `Promise` 的子类上调用，并且结果会是该子类类型的 Promise 对象。为此，子类的构造函数必须实现与 `Promise()` 构造函数相同的签名，即接受一个 `executor` 函数，该函数可以用 `resolve` 和 `reject` 回调函数作为参数进行调用。`Promise.reject()` 实际上相当于 `new Promise((resolve, reject) => reject(reason))` 的简写形式。

与 `Promise.resolve()` 不同，即使 `reason` 已经是一个 Promise 对象，`Promise.reject()` 方法也始终会将其封装在一个新的 `Promise` 对象中。

示例
--

### 使用 `Promise.reject()` 静态方法

```js
Promise.reject(new Error("失败")).then(
  () => {
    // 不会被调用
  },
  (error) => {
    console.error(error); // Stacktrace
  },
);
```

### reject 一个 promise 对象

与 `Promise.resolve` 不同，`Promise.reject` 方法不会重用已存在的 `Promise` 实例。它始终返回一个新的 `Promise` 实例，该实例封装了拒绝的原因（`reason`）。

```js
const p = Promise.resolve(1);
const rejected = Promise.reject(p);
console.log(rejected === p); // false
rejected.catch((v) => {
  console.log(v === p); // true
});
```

### 在非 Promise 构造函数上调用 reject()

`Promise.reject()` 方法是一个通用方法。它可以在任何实现与 `Promise()` 构造函数相同签名的构造函数上调用。例如，我们可以在一个构造函数上调用它，并传入 `console.log` 作为 `reject` 参数：

```js
class NotPromise {
  constructor(executor) {
    // “resolve”和“reject”函数的行为与原生 Promise 完全不同，但 `Promise.reject()` 方法以相同的方式调用它们。
    executor(
      (value) => console.log("已解决", value),
      (reason) => console.log("已拒绝", reason),
    );
  }
}

Promise.reject.call(NotPromise, "foo"); // 输出 "已拒绝 foo"
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.reject |

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

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

参见
--

* `Promise`


Promise.prototype.catch() - JavaScript

Promise.prototype.catch()
=========================

`Promise` 实例的 **`catch()`** 方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 `Promise` 对象，这可以允许你链式调用其他 promise 的方法。此方法是 `Promise.prototype.then(undefined, onRejected)` 的一种简写形式。

尝试一下
----

语法
--

```js
catch(onRejected)
```

### 参数

`onRejected`

一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 `catch()` 返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数：

`reason`

Promise 对象的拒绝值。

### 返回值

返回一个新的 `Promise`，无论当前的 promise 状态如何，这个新的 promise 在返回时总是处于待定状态。如果 `onRejected` 方法抛出了一个错误或者返回了一个被拒绝的 promise，那么这个新的 promise 也会被拒绝；否则它最终会被兑现。

描述
--

`catch` 方法用于在 Promise 链进行错误处理，因为它总是会返回一个 `Promise`，所以它可以和 `then()` 方法一样被链式调用。

如果一个 promise 被拒绝并且没有可调用的拒绝处理器（处理器可以是 `Promise.prototype.then()`、`Promise.prototype.catch()` 或 `Promise.prototype.finally()`），则拒绝事件由宿主环境来提供。在浏览器中，这将触发 `unhandledrejection` 事件。如果将一个处理器附加到一个已被拒绝，且已导致未处理的拒绝事件的 promise，将会触发 `rejectionhandled` 事件。

`catch()` 方法内部会调用当前 promise 对象的 `then()` 方法，并将 `undefined` 和 `onRejected` 作为参数传递给 `then()`。该调用的返回值直接被返回。如果你对这些方法进行封装，这一点是可以观察到的。

```js
// 重写原本的 Promise.prototype.then/catch 方法，只是为了添加一些日志
((Promise) => {
  const originalThen = Promise.prototype.then;
  const originalCatch = Promise.prototype.catch;

  Promise.prototype.then = function (...args) {
    console.log("在 %o 上调用 .then 方法，参数为：%o", this, args);
    return originalThen.apply(this, args);
  };
  Promise.prototype.catch = function (...args) {
    console.error("在 %o 上调用 .catch 方法，参数为：%o", this, args);
    return originalCatch.apply(this, args);
  };
})(Promise);

// 对已经解决的 Promise 调用 catch
Promise.resolve().catch(function XXX() {});

// 输出：
// 在 Promise{} 上调用 .catch，参数为：Arguments{1} [0: function XXX()]
// 在 Promise{} 上调用 .then，参数为：Arguments{2} [0: undefined, 1: function XXX()]
```

这意味着传入 `undefined` 仍然会导致返回的 promise 被拒绝，你必须传入一个函数来防止最终的 promise 被拒绝。

因为 `catch()` 只是单纯的调用了 `then()`，它支持子类化。

**备注：** 下面的示例抛出了 `Error` 的实例。与同步的 `throw` 语句一样，这被认为是一种良好的实践；否则，执行捕获的部分将不得不对参数进行检查，以查看它是字符串还是错误，并且你可能会丢失有用的信息，例如堆栈跟踪。

示例
--

### 在链式调用中使用 catch() 方法

```js
const p1 = new Promise((resolve, reject) => {
  resolve("成功！");
});

p1.then((value) => {
  console.log(value); // "成功！"
  throw new Error("噢，不！");
})
  .catch((e) => {
    console.error(e.message); // "噢，不！"
  })
  .then(
    () => console.log("在 catch 后，调用链恢复了"),
    () => console.log("因为有了 catch 而不会被触发"),
  );

// 下面的行为与上面相同
p1.then((value) => {
  console.log(value); // "成功！"
  return Promise.reject("噢，不！");
})
  .catch((e) => {
    console.error(e); // "噢，不！"
  })
  .then(
    () => console.log("在 catch 后，调用链恢复了"),
    () => console.log("因为有了 catch 而不会被触发"),
  );
```

### 抛出错误时的陷阱

大多数情况下，抛出错误会调用 `catch()` 方法：

```js
const p1 = new Promise((resolve, reject) => {
  throw new Error("哦吼！");
});

p1.catch((e) => {
  console.error(e); // "哦吼！"
});
```

在异步函数内部抛出的错误会像未捕获的错误一样：

```js
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error("未捕获的异常！");
  }, 1000);
});

p2.catch((e) => {
  console.error(e); // 永远不会被调用
});
```

在调用 `resolve` 之后抛出的错误会被忽略：

```js
const p3 = new Promise((resolve, reject) => {
  resolve();
  throw new Error("Silenced Exception!");
});

p3.catch((e) => {
  console.error(e); // 这里永远不会执行
});
```

### 如果 Promise 已兑现，catch() 不会被调用

```js
// 创建一个不会调用 onReject 的 Promise
const p1 = Promise.resolve("调用下一个");

const p2 = p1.catch((reason) => {
  // 这里永远不会执行
  console.error("p1 的 catch 函数被调用了！");
  console.error(reason);
});

p2.then(
  (value) => {
    console.log("下一个 Promise 的 onFulfilled 函数被调用了");
    console.log(value); // 调用下一个
  },
  (reason) => {
    console.log("下一个 Promise 的 onRejected 函数被调用了");
    console.log(reason);
  },
);
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise.prototype.catch |

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

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

参见
--

* `Promise`
* `Promise.prototype.then()`
* `Promise.prototype.finally()`


Promise() 构造函数 - JavaScript

Promise() 构造函数
==============

**`Promise()`** 构造函数创建 `Promise` 对象。它主要用于封装尚未支持 Promise 的基于回调的 API。

尝试一下
----

语法
--

```js
new Promise(executor)
```

**备注：** `Promise()` 只能通过 `new` 运算符来构造。如果尝试在没有使用 `new` 的情况下调用它，会抛出 `TypeError` 异常。

### 参数

`executor`

在构造函数中执行的 `function`。它接收两个函数作为参数：`resolveFunc` 和 `rejectFunc`。`executor` 中抛出的任何错误都会导致 Promise 被拒绝，并且返回值将被忽略。`executor` 的语义将在下文详细介绍。

### 返回值

当通过 `new` 关键字调用 `Promise` 构造函数时，它会返回一个 Promise 对象。当 `resolutionFunc` 或者 `rejectionFunc` 被调用时，该 Promise 对象就会变为*已解决*（resolved）。请注意，如果你调用 `resolveFunc` 或 `rejectFunc` 并传入另一个 Promise 对象作为参数，可以说该 Promise 对象“已解决”，但仍未“敲定（settled）”。有关更多解释，请参阅 Promise 描述。

描述
--

传统上（在 Promise 出现之前），设计上异步任务基于回调函数实现。

```js
readFile("./data.txt", (error, result) => {
  // 这个回调函数将在任务完成后被调用，返回最终的 `error` 或 `result`。
  // 任何依赖于返回结果的操作都必须在这个回调函数内定义。
});
// `readFile` 请求被发出后，此处的代码会立即执行。
// 它不会等待回调函数被调用，因此使 `readFile` 成为了“异步”的。
```

为了利用 Promise 提供的更好的可读性和语言特性，`Promise()` 构造函数允许将基于回调的 API 转换为基于 Promise 的 API。

**备注：** 如果你的任务已经基于 Promise 实现，你大概率不需要使用 `Promise()` 构造函数。

`executor` 是将回调函数的结果与 Promise 关联在一起的自定义代码。编写 `executor` 的工作由程序员完成。它的函数签名应该是：

```js
function executor(resolveFunc, rejectFunc) {
  // 通常，`executor` 函数用于封装某些接受回调函数作为参数的异步操作，比如上面的 `readFile` 函数
}
```

`resolveFunc` 和 `rejectFunc` 也是函数，你可以给它们任何实际的名称。它们的函数签名很简单：它们接受一个任意类型的参数。

```js
resolveFunc(value); // 解决时调用
rejectFunc(reason); // 拒绝时调用
```

传入 `resolveFunc` 的 `value` 参数可以是另一个 Promise 对象，在这种情况下，新构造的 Promise 对象的状态将“锁定”到传入的 Promise 对象（作为 resolution Promise 的一部分）。`rejectFunc` 的语义类似于 `throw` 语句，因此 `reason` 通常是一个 `Error` 实例。如果 `value` 或 `reason` 中有任意一个被省略，Promise 将会被兑现（fulfilled）或拒绝（rejected）为 `undefined`。

`executor` 的完成状态对 Promise 的状态影响有限：

* `executor` 函数的返回值会被忽略。`executor` 函数中的 `return` 语句仅影响控制流程，调整函数某个部分是否执行，但不会影响 Promise 的履行值。如果 `executor` 函数退出，且未来不可能调用 `resolveFunc` 或 `rejectFunc`（例如，没有安排异步任务），那么 Promise 将永远保持待定状态。
* 如果在 `executor` 函数中抛出错误，则 Promise 将被拒绝，除非 `resolveFunc` 或 `rejectFunc` 已经被调用。

**备注：** 待定的 Promise 的存在并不会阻止程序退出。如果事件循环为空，则程序会退出，尽管存在待定的 Promise（因为它们必然永远处于待定状态）。

以下是典型的 Promise 流程概述：

1. 在构造函数生成新的 `Promise` 对象时，它还会生成一对相应的 `resolveFunc` 和 `rejectFunc` 函数；它们与 `Promise` 对象“绑定”在一起。
2. `executor` 通常会封装某些提供基于回调的 API 的异步操作。回调函数（传给原始回调 API 的函数）在 `executor` 代码中定义，因此它可以访问 `resolveFunc` 和 `rejectFunc`。
3. `executor` 是同步调用的（在构造 `Promise` 时立即调用），并将 `resolveFunc` 和 `rejectFunc` 函数作为传入参数。
4. `executor` 中的代码有机会执行某些操作。异步任务的最终完成通过 `resolveFunc` 或 `rejectFunc` 引起的副作用与 Promise 实例进行通信。这个副作用让 `Promise` 对象变为“已解决”状态。
    * 如果先调用 `resolveFunc`，则传入的值将解决。Promise 可能会保持待定状态（如果传入了另一个 thenable 对象），变为已兑现状态（在传入非 thenable 值的大多数情况下），或者变为已拒绝状态（在解析值无效的情况下）。
    * 如果先调用 `rejectFunc`，则 Promise 立即变为已拒绝状态。
    * 一旦 `resolveFunc` 或 `rejectFunc` 中的一个被调用，Promise 将保持解决状态。只有第一次调用 `resolveFunc` 或 `rejectFunc` 会影响 Promise 的最终状态，随后对任一函数的调用都不能更改兑现值或拒绝原因，也不能将其最终状态从“已兑现”转换为“已拒绝”或相反。
    * 如果 `executor` 抛出错误，则 Promise 被拒绝。但是，如果 resolveFunc 或 rejectFunc 中的一个已经被调用（因此 Promise 已经被解决），则忽略该错误。
    * 解决 Promise 不一定会导致 Promise 变为已兑现或已拒绝（即已敲定）。Promise 可能仍处于待定状态，因为它可能是用另一个 thenable 对象解决的，但它的最终状态将与已解决的 thenable 对象一致。
5. 一旦 Promise 敲定，它会（异步地）调用任何通过 `then()`、`catch()` 或 `finally()` 关联的进一步处理程序。最终的兑现值或拒绝原因在调用时作为输入参数传给兑现和拒绝处理程序（请参阅 promise 的链式调用）。

例如，上面的基于回调的 `readFile` API 可以转换为基于 Promise 的 API。

```js
const readFilePromise = (path) =>
  new Promise((resolve, reject) => {
    readFile(path, (error, result) => {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      }
    });
  });

readFilePromise("./data.txt")
  .then((result) => console.log(result))
  .catch((error) => console.error("读取文件失败"));
```

### Resolver 函数

`resolveFunc` 解决函数有以下行为：

* 如果它被调用时传入了新建的 `Promise` 对象本身（即它所“绑定”的 Promise 对象），则 `Promise` 对象会被拒绝并抛出一个 `TypeError` 错误。
* 如果它使用一个非 thenable 的值（基本类型，或一个没有 `then` 属性或 `then` 属性不可调用的对象），则该 Promise 对象会被立即以该值兑现。
* 如果它被调用时传入了一个 thenable 对象（包括另一个 `Promise` 实例），则该 thenable 对象的 `then` 方法将被保存并在未来被调用（它总是异步调用）。`then` 方法将被调用并传入两个回调函数，这两个函数的行为与传递给 `executor` 函数的 `resolveFunc` 和 `rejectFunc` 函数完全相同。如果调用 `then` 方法时出现错误，则当前的 `Promise` 对象会被拒绝并抛出这个错误。

在最后一种情况下，这意味着像下面这样的代码：

```js
new Promise((resolve, reject) => {
  resolve(thenable);
});
```

大致相当于：

```js
new Promise((resolve, reject) => {
  try {
    thenable.then(
      (value) => resolve(value),
      (reason) => reject(reason),
    );
  } catch (e) {
    reject(e);
  }
});
```

但是在 `resolve(thenable)` 的情况中，有如下区别：

1. `resolve` 函数是同步调用的，因此再次调用 `resolve` 或 `reject` 函数没有任何影响，即使通过 `anotherPromise.then()` 绑定的处理程序尚未被调用。
2. `then` 方法是异步调用的，因此如果传入 thenable 对象，则该 `Promise` 对象不会被立即解决。

因为 `resolve` 函数再次调用时使用 `thenable.then()` 传递给它的任何值作为 `value` 参数，所以解决函数能够展开嵌套的 thenable 对象，其中一个 thenable 对象调用其 `onFulfilled` 处理程序并返回另一个 thenable 对象。这样做的效果是，真实的 `Promise` 对象的兑现处理器永远不会接收到 thenable 对象作为其兑现值。

示例
--

### 将基于回调的 API 转换为基于 Promise 的 API

为了让一个函数具有 Promise 功能，可以在适当的时候调用 `resolve` 和 `reject` 函数，并返回一个 Promise 对象。

```js
function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
}
```

### 调用 resolveFunc 的效果

调用 `resolveFunc` 函数会使 Promise 对象变为已解决状态，因此再次调用 `resolveFunc` 或 `rejectFunc` 函数没有任何效果。然而，Promise 对象可能处于以下任何状态之一：待定、已兑现或已拒绝。

在下面这个例子中，`pendingResolved` Promise 对象在创建时就已经被解决，因为它已经“锁定”以匹配内部 Promise 对象的最终状态，后续在 executor 函数中调用 `resolveOuter` 或 `rejectOuter` 或抛出错误对其最终状态没有影响。然而，内部 Promise 对象仍然处于待定状态，直到 100 毫秒后才被解决，因此外部 Promise 对象也处于待定状态：

```js
const pendingResolved = new Promise((resolveOuter, rejectOuter) => {
  resolveOuter(
    new Promise((resolveInner) => {
      setTimeout(() => {
        resolveInner("内部");
      }, 100);
    }),
  );
});
```

`fulfilledResolved` Promise 对象在被解决时立即变为已兑现状态，因为它以非 thenable 值解决。然而，在它被创建时，它是未解决的，因为 `resolve` 或 `reject` 函数还没有被调用。未解决的 Promise 对象必然是待定状态：

```js
const fulfilledResolved = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("外部");
  }, 100);
});
```

显然，调用 `rejectFunc` 函数会导致 Promise 对象被拒绝。然而，即使在调用 `resolveFunc` 回调函数时，也有两种方法可以使 Promise 对象立即被拒绝。

```js
// 1. 传入 Promise 本身
const rejectedResolved1 = new Promise((resolve) => {
  // 注意：resolve 必须异步调用，以便初始化 rejectedResolved1 变量
  setTimeout(() => resolve(rejectedResolved1)); // TypeError: Chaining cycle detected for promise #<Promise>
});

// 2. 传入一个在访问 `then` 属性时抛出异常的对象
const rejectedResolved2 = new Promise((resolve) => {
  resolve({
    get then() {
      throw new Error("无法访问 then 属性");
    },
  });
});
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-promise-constructor |

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

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

参见
--

* `core-js` 中 `Promise` 的 polyfill
* 使用 Promise


Promise.withResolvers() - JavaScript

Promise.withResolvers()
=======================

**`Promise.withResolvers()`** 静态方法返回一个对象，其包含一个新的 `Promise` 对象和两个函数，用于解决或拒绝它，对应于传入给 `Promise()` 构造函数执行器的两个参数。

语法
--

```js
Promise.withResolvers()
```

### 参数

无。

### 返回值

包含以下属性的普通对象：

`promise`

一个 `Promise` 对象。

`resolve`

一个函数，用于解决该 Promise。关于其语义，请参阅 `Promise()` 构造函数。

`reject`

一个函数，用于拒绝该 Promise。关于其语义，请参阅 `Promise()` 构造函数。

描述
--

`Promise.withResolvers()` 完全等同于以下代码：

```js
let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});
```

只是它更简洁，并且不需要使用 `let`。

使用 `Promise.withResolvers()` 关键的区别在于解决和拒绝函数现在与 Promise 本身处于同一作用域，而不是在执行器中被创建和一次性使用。这可能使得一些更高级的用例成为可能，例如在重复事件中重用它们，特别是在处理流和队列时。这通常也意味着相比在执行器内包装大量逻辑，嵌套会更少。

`Promise.withResolvers()` 是通用的且支持子类化，这意味着它可以在 `Promise` 的子类上调用，结果将包含一个该子类类型的 promise。要做到这一点，子类的构造函数必须实现与 `Promise()` 构造函数相同的签名——接受一个单独的 `executor` 函数，该函数可以用 `resolve` 和 `reject` 回调作为参数来调用。

示例
--

### 将流转换为异步可迭代对象

`Promise.withResolvers()` 的使用场景是，当你有一个 promise，需要通过无法包装在 promise 执行器内的某个事件监听器来解决或拒绝。以下示例将 Node.js 的可读流转换为异步可迭代对象。这里的每个 `promise` 代表一个可用的数据批次，每次读取当前批次时，就会为下一个批次创建一个新的 promise。请注意，事件监听器只附加了一次，但实际上每次都调用了不同版本的 `resolve` 和 `reject` 函数。

```js
async function\* readableToAsyncIterable(stream) {
  let { promise, resolve, reject } = Promise.withResolvers();
  stream.on("error", (error) => reject(error));
  stream.on("end", () => resolve());
  stream.on("readable", () => resolve());

  while (stream.readable) {
    await promise;
    let chunk;
    while ((chunk = stream.read())) {
      yield chunk;
    }
    ({ promise, resolve, reject } = Promise.withResolvers());
  }
}
```

### 在非 Promise 构造函数上调用 withResolvers()

`Promise.withResolvers()` 是一个通用方法。它可以在任何实现了与 `Promise()` 构造函数相同签名的构造函数上调用。例如，我们可以在一个将 `console.log` 作为 `resolve` 和 `reject` 函数传入给 `executor` 的构造函数上调用它：

```js
class NotPromise {
  constructor(executor) {
    // “resolve”和“reject”函数和原生的 promise 的行为完全不同
    // 但 Promise.withResolvers() 只是返回它们，就像是原生的 promise 一样
    executor(
      (value) => console.log("以", value, "解决"),
      (reason) => console.log("以", reason, "拒绝"),
    );
  }
}

const { promise, resolve, reject } = Promise.withResolvers.call(NotPromise);
resolve("hello");
// 输出：以 hello 解决
```

规范
--

| Specification |
| --- |
| ES Promise.withResolvers (2023) # sec-promise.withResolvers |

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

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

参见
--

* `core-js` 中 `Promise.withResolvers` 的 polyfill
* 使用 promise 指南
* `Promise`
* `Promise()` 构造函数


BigInt.prototype.toString() - JavaScript

BigInt.prototype.toString()
===========================

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

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

* Learn more
* See full compatibility
* Report feedback
**`toString()`** 方法返回一个字符串，表示指定 `BigInt` 对象。后面的 "n" 不是字符串的一部分。

尝试一下
----

语法
--
```

bigIntObj.toString([radix])
```

### 参数

`radix`可选

可选，介于 2 到 36 之间的整数，指定用于表示数值的基数。

### 返回值

表示指定 `BigInt` 对象的字符串。

### 异常

`RangeError`

如果 `toString()` 的基数小于 2 或大于 36, 则抛出 `RangeError`。

描述
--

`BigInt` 对象重写 `Object` 对象的 `toString()` 方法；它不继承 `Object.prototype.toString()`。对于 `BigInt` 对象，`toString()` 方法返回指定基数中对象的字符串表示形式。

`toString()` 方法解析其第一个参数，并尝试返回指定基数 (base) 的字符串表示形式。对于大于 10 的参数，使用字母表中的字母表示大于 9 的数字。例如，对于十六进制数（以 16 为基数），使用 a 到 f。

如果未指定基数，则假定首选基数为 10。

如果 `bigIntObj` 为负，则保留符号。即使基数是 2，情况也是如此；返回的字符串是 `bigIntObj` 的正二进制表示，前面是一个 `-` 符号，而不是 `bigIntObj` 的两个补码。

示例
--

### Using `toString`

```js
17n.toString(); // '17'
66n.toString(2); // '1000010'
254n.toString(16); // 'fe'
-10n.toString(2); // -1010'
-0xffn.toString(2); // '-11111111'
```

### Negative-zero `BigInt`

没有负零 `BigInt`，因为整数中没有负零。`-0.0` 是一个 IEEE 浮点概念，只出现在 JavaScript `Number` 类型中。

```js
(-0n).toString(); // '0'
BigInt(-0).toString(); // '0'
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-bigint.prototype.tostring |

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

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

请参阅
---

* `BigInt.prototype.toLocaleString()`
* `BigInt.prototype.valueOf()`
* `Number.prototype.toString()`


BigInt() constructor - JavaScript

BigInt() constructor
====================

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

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

* Learn more
* See full compatibility
* Report feedback
**`BigInt()`** 构造函数用来创建 `BigInt` 对象。

语法
--

```js
BigInt(value)
```

### 参数

`value`

被创建的对象的数值。可以是字符串或整数。

**备注：** `BigInt()` 不与 `new` 运算符一起使用。

示例
--

```js
BigInt(123);
// 123n
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-bigint-constructor |

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

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

参见
--

* `BigInt`


BigInt.prototype.valueOf() - JavaScript

BigInt.prototype.valueOf()
==========================

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

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

* Learn more
* See full compatibility
* Report feedback
**`valueOf()`** 方法返回 `BigInt` 对象包装的原始值。

尝试一下
----

语法
--
```

bigIntObj.valueOf()
```

### 返回值

表示指定 `BigInt` 对象的原始 BigInt 值。

示例
--

### Using `valueOf`

```js
typeof Object(1n); // object
typeof Object(1n).valueOf(); // bigint
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-bigint.prototype.valueof |

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

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

请参阅
---

* `BigInt.prototype.toString()`


BigInt.asIntN() - JavaScript

BigInt.asIntN()
===============

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

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

* Learn more
* See full compatibility
* Report feedback
**`BigInt.asIntN`** 静态方法将 `BigInt` 值转换为一个 -`2^(width-1)` 与 `2^(width-1)-1` 之间的有符号整数。

尝试一下
----

语法
--
```

BigInt.asIntN(width, bigint);
```

### 参数

`width`

可存储整数的位数。

`bigint`

要存储在指定位数上的整数。

### 返回值

`bigint` 模 (modulo) `2^width` 作为有符号整数的值。

示例
--

### 保持在 64 位范围内

`BigInt.asIntN()` 方法对于保持在 64 位 (64-bit) 算数范围内非常有用。

```js
const max = 2n \*\* (64n - 1n) - 1n;

BigInt.asIntN(64, max);
// ↪ 9223372036854775807n

BigInt.asIntN(64, max + 1n);
// ↪ -9223372036854775808n
// negative because of overflow
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-bigint.asintn |

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

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

请参阅
---

* `BigInt`
* `BigInt.asUintN()`


BigInt.prototype.toLocaleString() - JavaScript

BigInt.prototype.toLocaleString()
=================================

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

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

* Learn more
* See full compatibility
* Report feedback
**`toLocaleString()`** 方法返回一个表示给定 BigInt 对象的字符串，该字符串格式因不同语言而不同。在支持 `Intl.NumberFormat` API 的实现中，该方法仅是调用了 `Intl.NumberFormat` 方法。

尝试一下
----

语法
--

```js
toLocaleString()
toLocaleString(locales)
toLocaleString(locales, options)
```

### 参数

`locales` 和 `options` 参数使程序能够指定使用哪种语言格式化规则，允许定制该方法的行为（behavior）。

在支持 `Intl.NumberFormat` API 的实现中，这些参数与 `Intl.NumberFormat()` (en-US) 构造函数的参数完全对应。而对于不支持 `Intl.NumberFormat` 的实现，则要求函数忽略这两个参数，使得函数使用的区域（locale）以及返回的字符串的格式完全取决于实现。

`locales` 可选

表示缩写语言代码（BCP 47 language tag）的字符串，或由此类字符串组成的数组。对应于 `Intl.NumberFormat()` 构造函数的 `locales` (en-US) 参数。

在不支持 `Intl.NumberFormat` 的实现中，该参数会被忽略，并且通常会使用主机的区域设置。

`options` 可选

一个调整输出格式的对象。对应于 `Intl.NumberFormat()` 构造函数的 `options` (en-US) 参数。

在不支持 `Intl.NumberFormat` 的实现中，该参数会被忽略。

参见 `Intl.NumberFormat()` 构造函数 (en-US)以详细了解这些参数以及如何使用它们。

### 返回值

一个表示给定 BitInt 对象的字符串，该字符串格式因不同语言而不同。

在支持 `Intl.NumberFormat` 的实现中，此方法等价于 `new Intl.NumberFormat(locales, options).format(number)`。

性能
--

当需要对大量的数字进行格式化时，最好创建一个 `Intl.NumberFormat` 对象，并使用其 `format()` 方法提供的函数。

示例
--

### 使用 `toLocaleString`

没有指定区域（locale）时，返回一个使用默认区域和格式设置（options）的格式化字符串。

```js
const bigint = 3500n;

console.log(bigint.toLocaleString());
// "3,500" 如果区域为 en-US
```

### 使用 `locales`

这个例子展示了本地化数字格式的一些变体。为了获得应用程序用户界面中使用的语言的格式，请确保使用 `locales` 参数指定该语言（可能还有一些回退语言）：

```js
const bigint = 123456789123456789n;

// 德国使用句号表示千位
console.log(bigint.toLocaleString("de-DE"));
// 123.456.789.123.456.789

// 大多数说阿拉伯语的阿拉伯国家使用东阿拉伯数字
console.log(bigint.toLocaleString("ar-EG"));
// ١٢٣٬٤٥٦٬٧٨٩٬١٢٣٬٤٥٦٬٧٨٩

// 印度使用千、万、千万分隔符
console.log(bigint.toLocaleString("en-IN"));
// 1,23,45,67,89,12,34,56,789

// nu 扩展键要求使用编号系统，例如中文十进制数
console.log(bigint.toLocaleString("zh-Hans-CN-u-nu-hanidec"));
// 一二三,四五六,七八九,一二三,四五六,七八九

// 当使用的语言不被支持，例如
// 巴厘岛语，则可以包含一种回退语言，这里以印尼语为例
console.log(bigint.toLocaleString(["ban", "id"]));
// 123.456.789.123.456.789
```

### 使用 `options`

`toLocaleString` 提供的结果可以使用 `options` 参数进行自定义：

```js
const bigint = 123456789123456789n;

// 要求使用货币格式
console.log(
  bigint.toLocaleString("de-DE", { style: "currency", currency: "EUR" }),
);
// 123.456.789.123.456.789,00 €

// 日元不使用小数单位
console.log(
  bigint.toLocaleString("ja-JP", { style: "currency", currency: "JPY" }),
);
// ￥123,456,789,123,456,789

// 保留三位有效数字
console.log(bigint.toLocaleString("en-IN", { maximumSignificantDigits: 3 }));
// 1,23,00,00,00,00,00,00,000
```

规范
--

| Specification |
| --- |
| ECMAScript Internationalization API Specification # sup-bigint.prototype.tolocalestring |

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

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

参见
--

* `BigInt.prototype.toString()`


BigInt.asUintN() - JavaScript

BigInt.asUintN()
================

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

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

* Learn more
* See full compatibility
* Report feedback
**`BigInt.asUintN`** 静态方法将 `BigInt` 转换为一个 0 和 2^width-1 之间的无符号整数。

尝试一下
----

语法
--
```

BigInt.asUintN(width, bigint);
```

### 参数

`width`

可存储整数的位数。

`bigint`

要存储在指定位数上的整数。

### 返回值

`bigint` 模 (modulo) `2^width` 作为无符号整数的值。

示例
--

### 保持在 64 位范围内

`BigInt.asUintN()` 方法对于保持在 64 位 (64-bit) 算数范围内非常有用。

```js
const max = 2n \*\* 64n - 1n;

BigInt.asUintN(64, max);
// ↪ 18446744073709551615n

BigInt.asUintN(64, max + 1n);
// ↪ 0n
// zero because of overflow
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-bigint.asuintn |

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

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

请参阅
---

* `BigInt`
* `BigInt.asIntN()`


JSON.stringify() - JavaScript

JSON.stringify()
================

**`JSON.stringify()`** 方法将一个 JavaScript 对象或值转换为 JSON 字符串，如果指定了一个 replacer 函数，则可以选择性地替换值，或者指定的 replacer 是数组，则可选择性地仅包含数组指定的属性。

尝试一下
----

语法
--
```

JSON.stringify(value[, replacer [, space]])
```

### 参数

`value`

将要序列化成 一个 JSON 字符串的值。

`replacer` 可选

如果该参数是一个函数，则在序列化过程中，被序列化的值的每个属性都会经过该函数的转换和处理；如果该参数是一个数组，则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中；如果该参数为 null 或者未提供，则对象所有的属性都会被序列化。

`space` 可选

指定缩进用的空白字符串，用于美化输出（pretty-print）；如果参数是个数字，它代表有多少的空格；上限为 10。该值若小于 1，则意味着没有空格；如果该参数为字符串（当字符串长度超过 10 个字母，取其前 10 个字母），该字符串将被作为空格；如果该参数没有提供（或者为 null），将没有空格。

### 返回值

一个表示给定值的 JSON 字符串。

### 异常

* 当在循环引用时会抛出异常`TypeError` ("cyclic object value")（循环对象值）
* 当尝试去转换 `BigInt` 类型的值会抛出`TypeError` ("BigInt value can't be serialized in JSON")（BigInt 值不能 JSON 序列化）.
描述
--

`JSON.stringify()`将值转换为相应的 JSON 格式：

* 转换值如果有 toJSON() 方法，该方法定义什么值将被序列化。
* 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
* 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
* `undefined`、任意的函数以及 symbol 值，在序列化过程中会被忽略（出现在非数组对象的属性值中时）或者被转换成 `null`（出现在数组中时）。函数、undefined 被单独转换时，会返回 undefined，如`JSON.stringify(function(){})` or `JSON.stringify(undefined)`.
* 对包含循环引用的对象（对象之间相互引用，形成无限循环）执行此方法，会抛出错误。
* 所有以 symbol 为属性键的属性都会被完全忽略掉，即便 `replacer` 参数中强制指定包含了它们。
* Date 日期调用了 toJSON() 将其转换为了 string 字符串（同 Date.toISOString()），因此会被当做字符串处理。
* NaN 和 Infinity 格式的数值及 null 都会被当做 null。
* 其他类型的对象，包括 Map/Set/WeakMap/WeakSet，仅会序列化可枚举的属性。
示例
--

### 使用 JSON.stringify

```js
JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify("foo"); // '"foo"'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify({ x: 5 }); // '{"x":5}'

JSON.stringify({ x: 5, y: 6 });
// "{"x":5,"y":6}"

JSON.stringify([new Number(1), new String("false"), new Boolean(false)]);
// '[1,"false",false]'

JSON.stringify({ x: undefined, y: Object, z: Symbol("") });
// '{}'

JSON.stringify([undefined, Object, Symbol("")]);
// '[null,null,null]'

JSON.stringify({ [Symbol("foo")]: "foo" });
// '{}'

JSON.stringify({ [Symbol.for("foo")]: "foo" }, [Symbol.for("foo")]);
// '{}'

JSON.stringify({ [Symbol.for("foo")]: "foo" }, function (k, v) {
  if (typeof k === "symbol") {
    return "a symbol";
  }
});

// undefined

// 不可枚举的属性默认会被忽略：
JSON.stringify(
  Object.create(null, {
    x: { value: "x", enumerable: false },
    y: { value: "y", enumerable: true },
  }),
);

// "{"y":"y"}"
```

### `replacer` 参数

replacer 参数可以是一个函数或者一个数组。作为函数，它有两个参数，键（key）和值（value），它们都会被序列化。

在开始时，`replacer` 函数会被传入一个空字符串作为 `key` 值，代表着要被 `stringify` 的这个对象。随后每个对象或数组上的属性会被依次传入。

函数应当返回 JSON 字符串中的 value, 如下所示：

* 如果返回一个 `Number`, 转换成相应的字符串作为属性值被添加入 JSON 字符串。
* 如果返回一个 `String`, 该字符串作为属性值被添加入 JSON 字符串。
* 如果返回一个 `Boolean`, "true" 或者 "false" 作为属性值被添加入 JSON 字符串。
* 如果返回任何其他对象，该对象递归地序列化成 JSON 字符串，对每个属性调用 replacer 方法。除非该对象是一个函数，这种情况将不会被序列化成 JSON 字符串。
* 如果返回 undefined，该属性值不会在 JSON 字符串中输出。

**注意：** 不能用 replacer 方法，从数组中移除值（values），如若返回 undefined 或者一个函数，将会被 null 取代。

#### 示例 (function)
```

function replacer(key, value) {
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}

var foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
var jsonString = JSON.stringify(foo, replacer);
```

JSON 序列化结果为 `{"week":45,"month":7}`.

#### 示例 (array)

如果 `replacer` 是一个数组，数组的值代表将被序列化成 JSON 字符串的属性名。
```

JSON.stringify(foo, ['week', 'month']);
// '{"week":45,"month":7}', 只保留“week”和“month”属性值。
```

### `space` 参数

`space` 参数用来控制结果字符串里面的间距。如果是一个数字，则在字符串化时每一级别会比上一级别缩进多这个数字值的空格（最多 10 个空格）；如果是一个字符串，则每一级别会比上一级别多缩进该字符串（或该字符串的前 10 个字符）。

```js
JSON.stringify({ a: 2 }, null, " "); // '{\n "a": 2\n}'
```

使用制表符（\t）来缩进：

```js
JSON.stringify({ uno: 1, dos: 2 }, null, "\t");
// '{ \
// "uno": 1, \
// "dos": 2 \
// }'
```

### toJSON 方法

如果一个被序列化的对象拥有 `toJSON` 方法，那么该 `toJSON` 方法就会覆盖该对象默认的序列化行为：不是该对象被序列化，而是调用 `toJSON` 方法后的返回值会被序列化，例如：

```js
var obj = {
  foo: "foo",
  toJSON: function () {
    return "bar";
  },
};
JSON.stringify(obj); // '"bar"'
JSON.stringify({ x: obj }); // '{"x":"bar"}'
```

### 关于序列化循环引用的问题

由于 JSON 格式不支持对象引用（尽管有一个 IETF 草案存在），如果尝试编码带有循环引用的对象，将会抛出 `TypeError` 异常。

```js
const circularReference = {};
circularReference.myself = circularReference;

// 序列化循环引用会抛出 "TypeError: cyclic object value" 错误
JSON.stringify(circularReference);
```

要序列化循环引用，你可以使用支持循环引用的库（例如 Douglas Crockford 的 cycle.js），或者自己实现一个解决方案，这需要找到循环引用，并用可序列化的值替换（或移除）它们。

如果你在使用 `JSON.stringify()` 来深拷贝一个对象，你可能想要使用 `structuredClone()`，它支持循环引用。JavaScript 引擎的二进制序列化 API，比如 `v8.serialize()`，也支持循环引用。

### `JSON.stringify`用作 JavaScript

注意 JSON 不是 JavaScript 严格意义上的子集，在 JSON 中不需要省略两条终线（Line separator 和 Paragraph separator），但在 JavaScript 中需要被省略。因此，如果 JSON 被用作 JSONP 时，下面方法可以使用：
```

function jsFriendlyJSONStringify (s) {
    return JSON.stringify(s).
        replace(/\u2028/g, '\\u2028').
        replace(/\u2029/g, '\\u2029');
}

var s = {
    a: String.fromCharCode(0x2028),
    b: String.fromCharCode(0x2029)
};
try {
    eval('(' + JSON.stringify(s) + ')');
} catch (e) {
    console.log(e); // "SyntaxError: unterminated string literal"
}

// No need for a catch
eval('(' + jsFriendlyJSONStringify(s) + ')');

// console.log in Firefox unescapes the Unicode if
//   logged to console, so we use alert
alert(jsFriendlyJSONStringify(s)); // {"a":"\u2028","b":"\u2029"}
```

### 使用 JSON.stringify 结合 localStorage 的例子

一些时候，你想存储用户创建的一个对象，并且，即使在浏览器被关闭后仍能恢复该对象。下面的例子是 `JSON.stringify` 适用于这种情形的一个样板：

```js
// 创建一个示例数据
var session = {
  screens: [],
  state: true,
};
session.screens.push({ name: "screenA", width: 450, height: 250 });
session.screens.push({ name: "screenB", width: 650, height: 350 });
session.screens.push({ name: "screenC", width: 750, height: 120 });
session.screens.push({ name: "screenD", width: 250, height: 60 });
session.screens.push({ name: "screenE", width: 390, height: 120 });
session.screens.push({ name: "screenF", width: 1240, height: 650 });

// 使用 JSON.stringify 转换为 JSON 字符串
// 然后使用 localStorage 保存在 session 名称里
localStorage.setItem("session", JSON.stringify(session));

// 然后是如何转换通过 JSON.stringify 生成的字符串，该字符串以 JSON 格式保存在 localStorage 里
var restoredSession = JSON.parse(localStorage.getItem("session"));

// 现在 restoredSession 包含了保存在 localStorage 里的对象
console.log(restoredSession);
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-json.stringify |

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

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

参见
--

* `core-js` 中对现代 `JSON.stringify` 行为（符号和良好格式的 unicode）的 polyfill
* `JSON.parse()`


JSON.parse() - JavaScript

JSON.parse()
============

**`JSON.parse()`** 方法用来解析 JSON 字符串，构造由字符串描述的 JavaScript 值或对象。提供可选的 **reviver** 函数用以在返回之前对所得到的对象执行变换 (操作)。

尝试一下
----

语法
--

```js
JSON.parse(text)
JSON.parse(text, reviver)
```

### 参数

`text`

要被解析成 JavaScript 值的字符串，关于 JSON 的语法格式，请参考：`JSON`。

`reviver` 可选

转换器，如果传入该参数 (函数)，可以用来修改解析生成的原始值，调用时机在 parse 函数返回之前。

### 返回值

与给定的 JSON `text` 相对应的 `Object`、`Array`、string、number、boolean 或者 `null` 值。

### 异常

`SyntaxError`

若传入的字符串不符合 JSON 规范，则会抛出此异常。

示例
--

### 使用 `JSON.parse()`

```js
JSON.parse("{}"); // {}
JSON.parse("true"); // true
JSON.parse('"foo"'); // "foo"
JSON.parse('[1, 5, "false"]'); // [1, 5, "false"]
JSON.parse("null"); // null
```

### 使用 `reviver` 函数

如果指定了 `reviver` 函数，则解析出的 JavaScript 值（解析值）会经过一次转换后才将被最终返回（返回值）。更具体点讲就是：解析值本身以及它所包含的所有属性，会按照一定的顺序（从最最里层的属性开始，一级级往外，最终到达顶层，也就是解析值本身）分别的去调用 `reviver` 函数，在调用过程中，当前属性所属的对象会作为 `this` 值，当前属性名和属性值会分别作为第一个和第二个参数传入 `reviver` 中。如果 `reviver` 返回 `undefined`，则当前属性会从所属对象中删除，如果返回了其他值，则返回的值会成为当前属性新的属性值。

当遍历到最顶层的值（解析值）时，传入 `reviver` 函数的参数会是空字符串 `""`（因为此时已经没有真正的属性）和当前的解析值（有可能已经被修改过了），当前的 `this` 值会是 `{"": 修改过的解析值}`，在编写 `reviver` 函数时，要注意到这个特例。（这个函数的遍历顺序依照：从最内层开始，按照层级顺序，依次向外遍历）

```js
JSON.parse('{"p": 5}', function (k, v) {
  if (k === "") return v; // 如果到了最顶层，则直接返回属性值，
  return v \* 2; // 否则将属性值变为原来的 2 倍。
}); // { p: 10 }

JSON.parse('{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}', function (k, v) {
  console.log(k); // 输出当前的属性名，从而得知遍历顺序是从内向外的，
  // 最后一个属性名会是个空字符串。
  return v; // 返回原始属性值，相当于没有传递 reviver 参数。
});

// 1
// 2
// 4
// 6
// 5
// 3
// ""
```

### `JSON.parse()` 不允许用逗号作为结尾

```js
// both will throw a SyntaxError
JSON.parse("[1, 2, 3, 4, ]");
JSON.parse('{"foo" : 1, }');
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-json.parse |

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

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

参见
--

* `JSON.stringify()`


AsyncGeneratorFunction() 构造函数 - JavaScript

AsyncGeneratorFunction() 构造函数
=============================

**`AsyncGeneratorFunction()`** 构造函数创建 `AsyncGeneratorFunction` 对象。

注意，`AsyncGeneratorFunction` 不是全局对象。它可以通过执行以下代码获取。

```js
const AsyncGeneratorFunction = async function\* () {}.constructor;
```

`AsyncGeneratorFunction()` 构造函数不应直接使用，并且所有在 `Function()` 的描述中提到的注意事项也适用于 `AsyncGeneratorFunction()`。

语法
--

```js
new AsyncGeneratorFunction(functionBody)
new AsyncGeneratorFunction(arg1, functionBody)
new AsyncGeneratorFunction(arg1, arg2, functionBody)
new AsyncGeneratorFunction(arg1, arg2, /\* …, \*/ argN, functionBody)

AsyncGeneratorFunction(functionBody)
AsyncGeneratorFunction(arg1, functionBody)
AsyncGeneratorFunction(arg1, arg2, functionBody)
AsyncGeneratorFunction(arg1, arg2, /\* …, \*/ argN, functionBody)
```

**备注：** 无论是否使用 `new` 调用 `AsyncGeneratorFunction()`，都可以创建一个新的 `AsyncGeneratorFunction` 实例。

### 参数

参见 `Function()`。

示例
--

### 使用构造函数

以下示例使用 `AsyncGeneratorFunction` 构造函数创建一个异步生成器函数。

```js
const AsyncGeneratorFunction = async function\* () {}.constructor;
const createAsyncGenerator = new AsyncGeneratorFunction("a", "yield a \* 2");
const asyncGen = createAsyncGenerator(10);
asyncGen.next().then((res) => console.log(res.value)); // 20
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-asyncgeneratorfunction-constructor |

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

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

参见
--

* `async function*`
* `async function*` 表达式
* `Function()` 构造函数
* 迭代器和生成器指南
* 函数


SharedArrayBuffer.prototype.maxByteLength - JavaScript

SharedArrayBuffer.prototype.maxByteLength
=========================================

`SharedArrayBuffer` 实例的 **`maxByteLength`** 访问器属性返回当前 `SharedArrayBuffer` 可以增大到的最大长度（以字节为单位）。

描述
--

`maxByteLength` 属性是一个访问器属性，其设置访问器函数为 `undefined`，因此你只能读取该属性。该属性的值在构造数组时确定。通过 `SharedArrayBuffer()` 构造函数的 `maxByteLength` 选项来设置该值，并且无法更改。

如果当前 `SharedArrayBuffer` 构造时时没有指定 `maxByteLength` 的值，这个属性会返回一个等于 `SharedArrayBuffer` 的 `byteLength` 属性值的数值。

示例
--

### 使用 maxByteLength

在这个示例中，我们创建一个 8 字节缓冲区，该缓冲区可调整到的最大长度是 16 字节，然后返回其 `maxByteLength`：

```js
const buffer = new SharedArrayBuffer(8, { maxByteLength: 16 });

buffer.maxByteLength; // 16
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-get-sharedarraybuffer.prototype.maxbytelength |

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

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

参见
--

* `SharedArrayBuffer`


SharedArrayBuffer.prototype.grow() - JavaScript

SharedArrayBuffer.prototype.grow()
==================================

`SharedArrayBuffer` 实例的 **`grow()`** 方法将 `SharedArrayBuffer` 增大到以字节为单位的指定大小。

语法
--

```js
grow(newLength)
```

### 参数

`newLength`

新的长度，以字节为单位，`SharedArrayBuffer` 调整后的大小。

### 返回值

无（`undefined`）。

### 异常

`TypeError`

如果当前的 `SharedArrayBuffer` 不可增大，则抛出该异常。

`RangeError`

如果 `newLength` 大于当前 `SharedArrayBuffer` 的 `maxByteLength` 或小于 `byteLength`，则抛出该异常。

描述
--

`grow()` 方将 `SharedArrayBuffer` 增大到 `newLength` 参数指定的大小，前提是 `SharedArrayBuffer` 是可增大的，并且新的大小小于等于当前 `SharedArrayBuffer` 的 `maxByteLength`。新字节被初始化为 0。

示例
--

### 使用 grow()

在这个示例中，我们创建一个 8 字节缓冲区，该缓冲区可调整大小到的最大长度是 16 字节，然后检查其 `growable` 属性，如果 `growable` 返回 `true`，则将其增大：

```js
const buffer = new SharedArrayBuffer(8, { maxByteLength: 16 });

if (buffer.growable) {
  console.log("SAB 是可增大的！");
  buffer.grow(12);
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-sharedarraybuffer.prototype.grow |

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

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

参见
--

* `SharedArrayBuffer`
* `SharedArrayBuffer.prototype.growable`
* `SharedArrayBuffer.prototype.maxByteLength`


SharedArrayBuffer.prototype.byteLength - JavaScript

SharedArrayBuffer.prototype.byteLength
======================================

`SharedArrayBuffer` 实例的 **`byteLength`** 访问器属性返回该 `SharedArrayBuffer` 的大小（以字节为单位）。

尝试一下
----

描述
--

`byteLength` 属性是一个访问器属性，它的设置访问器函数为 `undefined`，这意味着你只能读取该属性。该值在创建共享数组时就确定了，不能更改。

示例
--

### 使用 byteLength

```js
const sab = new SharedArrayBuffer(1024);
sab.byteLength; // 1024
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-get-sharedarraybuffer.prototype.bytelength |

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

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

参见
--

* `SharedArrayBuffer`


SharedArrayBuffer.prototype.slice() - JavaScript

SharedArrayBuffer.prototype.slice()
===================================

`SharedArrayBuffer` 实例的 **`slice()`** 方法返回一个新的 `SharedArrayBuffer`，其包含当前 `SharedArrayBuffer` 从 `start` 开始（包含）到 `end` 结束（不含）的字节内容的副本。如果 `start` 或 `end` 为负数，则表示从数组末尾开始计数的索引，即与从开头开始的方向相反。

尝试一下
----

语法
--

```js
slice()
slice(start)
slice(start, end)
```

### 参数

`start` 可选

要开始提取的位置索引（从 0 开始），将被转换为整数。

* 负数索引将会从缓冲区末尾开始计算——如果 `start < 0`，那么将会使用 `start + buffer.length`。
* 如果 `start < -buffer.length` 或省略了 `start`，则会使用 `0`。
* 如果 `start >= buffer.length`，则不会提取任何内容。

`end` 可选

要结束提取的位置索引（从 0 开始），将被转换为整数。`slice()` 提取到但不包括 `end`。

* 负数索引将会从缓冲区末尾开始计算——如果 `end < 0`，那么将会使用 `end + buffer.length`。
* 如果 `end < -buffer.length`，则会使用 `0`。
* 如果 `end >= buffer.length` 或省略了 `end`，则会使用 `buffer.length`，则会导致直到末尾的所有元素都被提取。
* 如果标准化后的 `end` 位置在 `start` 位置之前，则不会提取任何内容。

### 返回值

一个新的 `SharedArrayBuffer`，包含提取的元素。

示例
--

### 使用 slice()

```js
const sab = new SharedArrayBuffer(1024);
sab.slice(); // SharedArrayBuffer { byteLength: 1024 }
sab.slice(2); // SharedArrayBuffer { byteLength: 1022 }
sab.slice(-2); // SharedArrayBuffer { byteLength: 2 }
sab.slice(0, 1); // SharedArrayBuffer { byteLength: 1 }
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-sharedarraybuffer.prototype.slice |

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

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

参见
--

* `SharedArrayBuffer`
* `ArrayBuffer.prototype.slice()`


SharedArrayBuffer[@@species] - JavaScript

SharedArrayBuffer[@@species]
============================

**`SharedArrayBuffer[@@species]`** 静态访问器属性返回用于构造 `SharedArrayBuffer` 方法返回值的构造函数。

**警告：** `@@species` 的存在允许任意代码的执行，这可能导致安全漏洞。它还使某些优化变得更加困难。引擎实现者正在调查是否要移除此特性。如果可能，请避免依赖它。

语法
--

```js
SharedArrayBuffer[Symbol.species]
```

### 返回值

调用 `get @@species` 构造函数（`this`）的值。返回值用于构造创建新数组缓冲区的数组缓冲区方法的返回值。

描述
--

`@@species` 访问器属性返回 `SharedArrayBuffer` 对象的构造函数。子类构造函数可以重写它来改变构造函数赋值。默认实现大概是：

```js
// 用于说明而假设的底层实现
class SharedArrayBuffer {
  static get [Symbol.species]() {
    return this;
  }
}
```

由于这种多态实现，默认情况下，派生子类的 `@@species` 也会返回自身的构造函数。

```js
class SubArrayBuffer extends SharedArrayBuffer {}
SubArrayBuffer[Symbol.species] === SharedArrayBuffer; // true
```

在调用不会更改现有数组，而是返回一个新的数组缓冲实例的方法（例如，`slice()`）时，该数组的 `constructor[@@species]` 会被访问。返回的构造函数将被用于构造该数组缓冲区方法的返回值。

示例
--

### 普通对象中的 species

`@@species` 属性返回默认的构造函数，即 `SharedArrayBuffer` 的构造函数 `SharedArrayBuffer`。

```js
SharedArrayBuffer[Symbol.species]; // function SharedArrayBuffer()
```

### 派生对象中的 species

在自定义的 `SharedArrayBuffer` 子类实例中，例如 `MySharedArrayBuffer`，`MySharedArrayBuffer` 的 species 是 `MySharedArrayBuffer` 构造函数。但是，你可能希望重写它，以便在派生类方法中返回父类 `SharedArrayBuffer` 对象：

```js
class MySharedArrayBuffer extends SharedArrayBuffer {
  // 重写 MySharedArrayBuffer species 来返回父类 SharedArrayBuffer 构造函数
  static get [Symbol.species]() {
    return SharedArrayBuffer;
  }
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-sharedarraybuffer-@@species |

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

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

参见
--

* `SharedArrayBuffer`
* `Symbol.species`


SharedArrayBuffer.prototype.growable - JavaScript

SharedArrayBuffer.prototype.growable
====================================

`SharedArrayBuffer` 实例的 **`growable`** 访问器属性返回该 `SharedArrayBuffer` 是否可增大。

描述
--

`growable` 属性是一个访问器属性，其设置访问器函数为 `undefined`，因此你只能读取该属性。该属性的值在构造数组时确定。如果在构造函数中 `maxByteLength` 选项被设置，`growable` 将返回 `true`；否则，它将返回 `false`。

示例
--

### 使用 growable

在这个示例中，我们创建一个 8 字节缓冲区，该缓冲区可调整大小到的最大长度是 16 字节，然后检查其 `growable` 属性，如果 `growable` 返回 `true`，则增大它：

```js
const buffer = new SharedArrayBuffer(8, { maxByteLength: 16 });

if (buffer.growable) {
  console.log("SAB 是可增大的！");
  buffer.grow(12);
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-get-sharedarraybuffer.prototype.growable |

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

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

参见
--

* `SharedArrayBuffer`
* `SharedArrayBuffer.prototype.grow()`
* `SharedArrayBuffer.prototype.maxByteLength`


SharedArrayBuffer() 构造函数 - JavaScript

SharedArrayBuffer() 构造函数
========================

**备注：** `SharedArrayBuffer` 构造函数可能并不总是全局可用的，除非满足某些安全要求。

**`SharedArrayBuffer()`** 构造函数创建 `SharedArrayBuffer` 对象。

尝试一下
----

语法
--

```js
new SharedArrayBuffer(length)
new SharedArrayBuffer(length, options)
```

**备注：** `SharedArrayBuffer()` 只能通过 `new` 来调用。不带 `new` 调用会抛出 `TypeError`。

### 参数

`length`

要创建的数组缓冲区大小，以字节为单位。

`options` 可选

一个对象，包含以下属性：

`maxByteLength` 可选

该共享数组缓冲区可以调整到的最大大小，以字节为单位。

### 返回值

一个指定大小的新 `SharedArrayBuffer` 对象，如果指定了 `maxByteLength`，则其 `maxByteLength` 属性被设置为指定的值。其内容被初始化为 0。

示例
--

### 总是使用 new 运算符来创建 SharedArrayBuffer

`SharedArrayBuffer` 构造函数必须使用 `new` 运算符来构造。将 `SharedArrayBuffer` 构造函数作为函数，不通过 `new` 调用会抛出 `TypeError`。

```js
const sab = SharedArrayBuffer(1024);
// TypeError: calling a builtin SharedArrayBuffer constructor
// 不带 new 调用是不行的
```

```js
const sab = new SharedArrayBuffer(1024);
```

### 增大可增大的 SharedArrayBuffer

在这个示例中，我们创建了一个 8 字节的缓冲区，其可增大到的最大长度为 16 字节，然后 `grow()` 它到 12 字节：

```js
const buffer = new SharedArrayBuffer(8, { maxByteLength: 16 });

buffer.grow(12);
```

**备注：** 推荐设置 `maxByteLength` 为使用场景下最低的大小，不要超过 `1073741824`（1GB）以减小内存溢出风险。

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-sharedarraybuffer-constructor |

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

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

参见
--

* `Atomics`
* `ArrayBuffer`
* JavaScript 类型化数组指南


Boolean() 构造函数 - JavaScript

Boolean() 构造函数
==============

**`Boolean()`** 构造函数可以创建 `Boolean` 对象或返回布尔类型的原始值。

尝试一下
----

语法
--

```js
new Boolean(value)
Boolean(value)
```

**备注：** 调用 `Boolean()` 时可以使用或不使用 `new`，但是效果不同。参见返回值部分。

### 参数

`value`

`Boolean` 对象的初始值。

### 返回值

当 `Boolean()` 作为构造函数调用时（使用 `new`），将创建 `Boolean` 对象，它**不是**一个原始值。

当 `Boolean()` 作为普通函数调用时（不使用 `new`），它将参数强制转换为布尔原始值。

**警告：** 你会发现你很少会使用到 `Boolean` 构造函数。

描述
--

作为第一个参数传递的值被转换为布尔值 。如果该值被省略或为 `0`、`-0`、`0n`、`null`、`false`、`NaN`、`undefined` 或空字符串（`""`），那么该对象的初始值为 `false`。所有其他的值，包括任何对象、空数组（`[]`）或字符串 `"false"`，都会创建一个初始值为 `true` 的对象。

**备注：** 当非标准属性 `document.all` 被用作该构造函数的参数时，结果是一个值为 `false` 的 `Boolean` 对象。这个属性是遗留的和非标准的，不应该被使用。

示例
--

### 使用初始值 false 创建 Boolean 对象

```js
const bZero = new Boolean(0);
const bNull = new Boolean(null);
const bEmptyString = new Boolean("");
const bfalse = new Boolean(false);

typeof bfalse; // "object"
Boolean(bfalse); // true
```

请注意，用 `Boolean()` 将 `Boolean` 对象转换为原始值的结果总是 `true`，即使该对象的值为 `false`。因此，总是建议避免构造 `Boolean` 包装对象。

如果你需要从包装对象中取出原始值，不要使用 `Boolean()` 函数，而是使用对象的 `valueOf()` 方法。

```js
const bfalse = new Boolean(false);

bfalse.valueOf(); // false
```

### 使用初始值 true 创建 Boolean 对象

```js
const btrue = new Boolean(true);
const btrueString = new Boolean("true");
const bfalseString = new Boolean("false");
const bSuLin = new Boolean("Su Lin");
const bArrayProto = new Boolean([]);
const bObjProto = new Boolean({});
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-boolean-constructor |

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

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

参见
--

* Boolean


Boolean.prototype.valueOf() - JavaScript

Boolean.prototype.valueOf()
===========================

**`valueOf()`** 方法返回一个`Boolean`对象的原始值。

尝试一下
----

语法
--
```

bool.valueOf()
```

### 返回值

给定`Boolean`对象的原始值

描述
--

`Boolean`的 `valueOf` 方法返回一个`Boolean`对象或`Boolean`字面量的原始值作为布尔数据类型。

该方法通常在 JavaScript 内部调用，而不是在代码中显式调用。

示例
--

### 使用 `valueOf`

```js
x = new Boolean();
myVar = x.valueOf(); // assigns false to myVar
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-boolean.prototype.valueof |

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

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

参见
--

* `Object.prototype.valueOf()`


Boolean.prototype.toString() - JavaScript

Boolean.prototype.toString()
============================

**`toString()`** 方法返回表示指定的布尔对象的字符串。

尝试一下
----

语法
--

```js
toString()
```

### 返回值

一个表示特定 `Boolean` 对象的字符串。

描述
--

`Boolean` 对象覆盖了 `Object` 对象的 `toString` 方法。并没有继承 `Object.prototype.toString()`。对于布尔对象，`toString` 方法返回一个表示该对象的字符串。

当一个 `Boolean` 对象作为文本值或进行字符串连接时，JavaScript 会自动调用其 `toString` 方法。

对于 `Boolean` 对象或值，内置的 `toString` 方法返回字符串 `"true"` 或 `"false"`，具体返回哪个取决于布尔对象的值。

示例
--

### 使用 toString()

下面的代码，`flag.toString()` 返回 `"true"`：

```js
const flag = new Boolean(true);
const myVar = flag.toString();
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-boolean.prototype.tostring |

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

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

参见
--

* `Object.prototype.toString()`


Error.prototype.message - JavaScript

Error.prototype.message
=======================

概述
--

**`message`** 属性是有关错误信息，人类易读的（human-readable）描述。

描述
--

如果该属性已经被设置，则该属性包含了错误的一个简短描述。SpiderMonkey 大量应用 `message` 属性在异常方面。 `message` 属性结合 `name` 属性一起被 `Error.prototype.toString()` 方法用来创建错误的字符串形式。

默认情况下，`message` 属性是一个空字符串，但是可以通过指定一段信息作为 `Error constructor` 的第一个参数创建一个实例来改变该属性值。

示例
--

### 示例：抛出一个自定义错误

```js
var e = new Error("Could not parse input"); // e.message is "Could not parse input"
throw e;
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-error.prototype.message |

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

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

参见
--

* `Error.prototype.name`
* `Error.prototype.toString()`


Error.prototype.columnNumber - JavaScript

Error.prototype.columnNumber
============================

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

\*\*`columnNumber`\*\*属性包含引发此错误的文件行中的列号。

示例
--

### 使用 `columnNumber`

```js
var e = new Error("Could not parse input");
throw e;
console.log(e.columnNumber); // 0
```

规范
--

#### No specification found

No specification data found for `javascript.builtins.Error.columnNumber`.
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.

参见
--

* `Error.prototype.stack`
非标准
* `Error.prototype.lineNumber`
非标准
* `Error.prototype.fileName`
非标准


Error: cause - JavaScript

Error: cause
============

`Error` 实例中的 **`cause`** 数据属性指示导致该错误的具体原始原因。

在捕获错误时，我们可能会使用更具体或更加实用的信息对错误进行包装，再将其重新抛出。`cause` 属性就用于这一场景，以便仍然可以访问原始的错误。

取值
--

它通过 `options.cause` 参数被传入 `Error()` 构造函数，并且有可能不存在。

| `Error: cause` 的属性特性 |
| --- |
| 可写 | 是 |
| 可枚举 | 否 |
| 可配置 | 是 |

描述
--

`cause` 的值可以是任何类型。你不应该假设捕获错误的 `cause` 属性是一个 `Error`，正如在 `catch` 语句中绑定的变量未必一定是 `Error`。下文“将结构化的数据作为 cause”示例展示了刻意不提供 `Error` 作为 `cause` 的情况。

示例
--

### 重新抛出包含 cause 的错误

有时，捕获错误并使用新的错误信息将其重新抛出是很有用的。在这种情况下，你应该将原始错误传递给新的 `Error` 的构造函数，如下所示：

```js
try {
  connectToDatabase();
} catch (err) {
  throw new Error("Connecting to database failed.", { cause: err });
}
```

更详细的示例请参阅错误 > 区分相似的错误。

### 将结构化的数据作为 cause

为开发者理解而编写的错误消息可能并不适合机器解析，因为它们会受到表达方式改变（rewording），或标点符号改变的影响，破坏已有解析器的正常使用。因此，当从函数中抛出错误时，你可以提供结构化的数据作为错误原因（即 `cause` 字段）供机器解析，以此替代人类可读的错误消息。

```js
function makeRSA(p, q) {
  if (!Number.isInteger(p) || !Number.isInteger(q)) {
    throw new Error("RSA key generation requires integer inputs.", {
      cause: { code: "NonInteger", values: [p, q] },
    });
  }
  if (!areCoprime(p, q)) {
    throw new Error("RSA key generation requires two co-prime integers.", {
      cause: { code: "NonCoprime", values: [p, q] },
    });
  }
  // rsa algorithm…
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-installerrorcause |

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

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

参见
--

* `Error.prototype.message`
* `Error.prototype.toString()`


Error.prototype.name - JavaScript

Error.prototype.name
====================

概述
--

**`name`** 属性表示 error 类型的名称。初始值为"Error".

描述
--

默认情况下，`Error`对象的`name`属性值为"Error".`name 属性和``message`属性一起，通过调用`Error.prototype.toString()`方法，会作为最后异常信息的字符串表示。

示例
--

### 示例：抛出一个自定义错误

```js
var e = new Error("Malformed input"); // e.name 默认是"Error"

e.name = "ParseError"; // 修改之后，e.toString() 会成为下面这样的字符串
throw e; // "ParseError: Malformed input"
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-error.prototype.name |

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

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

参见
--

* `Error.prototype.message`
* `Error.prototype.toString()`


Error.prototype.toString() - JavaScript

Error.prototype.toString()
==========================

**`toString()`** 方法返回一个表示指定 `Error` 对象的字符串。

语法
--

```js
toString()
```

### 返回值

一个表示指定 `Error` 对象的字符串。

描述
--

`Error` 对象覆盖了 `Object.prototype.toString()` 方法。该方法实现如下（假定 `Object` 和 `String` 没有被更改）：

```js
Error.prototype.toString = function () {
  "use strict";

  const obj = Object(this);
  if (obj !== this) {
    throw new TypeError();
  }

  let name = this.name;
  name = name === undefined ? "Error" : String(name);

  let msg = this.message;
  msg = msg === undefined ? "" : String(msg);

  if (name === "") {
    return msg;
  }
  if (msg === "") {
    return name;
  }

  return name + ": " + msg;
};
```

示例
--

### 使用 toString()

```js
const e1 = new Error("fatal error");
console.log(e1.toString()); // 'Error: fatal error'

const e2 = new Error("fatal error");
e2.name = undefined;
console.log(e2.toString()); // 'Error: fatal error'

const e3 = new Error("fatal error");
e3.name = "";
console.log(e3.toString()); // 'fatal error'

const e4 = new Error("fatal error");
e4.name = "";
e4.message = undefined;
console.log(e4.toString()); // ''

const e5 = new Error("fatal error");
e5.name = "hello";
e5.message = undefined;
console.log(e5.toString()); // 'hello'
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-error.prototype.tostring |

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

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

参见
--

* `core-js` 中关于 `Error.prototype.toString` 的 polyfill（修复了多个错误）


Error.prototype.stack - JavaScript

Error.prototype.stack
=====================

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

`Error`对象作为一个非标准的栈属性提供了一种函数追踪方式。无论这个函数被被调用，处于什么模式，来自于哪一行或者哪个文件，有着什么样的参数。这个栈产生于最近一次调用最早的那次调用，返回原始的全局作用域调用

描述
--

每个步骤都会被分为单独的一行以这个函数的名字作为开始（如果不是一个来自于全局作用域的调用），然后通过一个 `@` 符号标记一个文件的位置（尤其是当一个函数构造错误并且作为错误被抛出，并且如果能定位到这个文件的位置，那么会使用冒号显示行号。（提示）`Error` 对象在错误跑出时同样能处理并渲染出文件名，行号和列号属性（但是仅仅限于错误。而不是追踪他的路径）

注意这是 Firefox 定义的格式，并没有标准的定义。但是 Safari 6+ 和 Opera 12- 定义了一种非常相似的格式。其他使用 JavaScript V8 引擎的浏览器（例如 Chrome、Opera 15+，安卓浏览器）和 IE 10+，定义了一种不同的格式（可参见 error.stack 文档）

堆栈中的参数值：Firefox 14 版本之前是 (Firefox bug 744842) 函数名会随着参数值会在添加 @符号之前被立即转换成用圆括号包裹的 string 类型。然而对象或者数组等其他类型似乎会被转换成`"[object Object]"`并且这种格式不能回退到之前实际上的对象，而纯值会被渲染（或许这种在 Firefox 14 中仍有这种可能，使用 `arguments.callee.caller.arguments` 更加简单。因为函数名可以使用 `arguments.callee.caller.name` 渲染）。`"undefined"` 被显示为 `"(void 0)"` 不过要注意的是如果是字符串类型的参数会直接以类似 `"@"`, `"("`, `")"` 格式通过编译（或者是包含在文件名中）。你不能简单的依赖这些将它分成多个组件，但是，对于 Firefox 14 及以后的版本来说，这些都不是问题

不同的浏览器会在不同时期设置这个值。例如，Firefox 在创建`Error`对象时设置它，然而 PhantomJS 是在当且仅当它抛出 `Error`时，并且MSDN docs 似乎也实现了 PhantomJS 的方式。

示例
--

下面这段 html 代码展示了`stack` 属性的使用方法

```html
<!doctype html>
<meta charset="UTF-8" />
<title>Stack Trace Example</title>
<body>
  <script>
 function trace() {
 try {
 throw new Error("myError");
 } catch (e) {
 alert(e.stack);
 }
 }
 function b() {
 trace();
 }
 function a() {
 b(3, 4, "\n\n", undefined, {});
 }
 a("first call, firstarg");
 </script>
</body>
```

假设上面这段代码被保存在 Windows 系统下的 `C:\example.html` 在处理过程中抛出如下所示的错误信息

Firefox 30 及以上版本的浏览器会包含以列号为开始 (Firefox bug 762556):
```

trace@file:///C:/example.html:9:17
b@file:///C:/example.html:16:13
a@file:///C:/example.html:19:13
@file:///C:/example.html:21:9
```

Firefox 14 to Firefox 29:
```

trace@file:///C:/example.html:9
b@file:///C:/example.html:16
a@file:///C:/example.html:19
@file:///C:/example.html:21
```

Firefox 13 及更早版本的浏览器会抛出如下信息：
```

Error("myError")@:0
trace()@file:///C:/example.html:9
b(3,4,"\n\n",(void 0),[object Object])@file:///C:/example.html:16
a("first call, firstarg")@file:///C:/example.html:19
@file:///C:/example.html:21
```

### Stack of eval'ed code

Firefox30 以 Gecko 30 格式开头，`Function()` 和 `eval()` 调用产生的错误代码堆栈，现在在调用内部通过行号和列号以更加详细的格式向我们展示出来。函数调用显示为`"> Function"` 而 eval 调用则是 `"> eval"`这样。下面来看这个Firefox bug 332176.

```js
try {
  new Function("throw new Error()")();
} catch (e) {
  console.log(e.stack);
}

// anonymous@file:///C:/example.html line 7 > Function:1:1
// @file:///C:/example.html:7:6

try {
  eval("eval('FAIL')");
} catch (x) {
  console.log(x.stack);
}

// @file:///C:/example.html line 7 > eval line 1 > eval:1:1
// @file:///C:/example.html line 7 > eval:1:1
// @file:///C:/example.html:7:6
```

你也可以使用`//# sourceURL` 命名 eval 源的指令。也可以查看在 Debugger文档中的Debug eval 源 (en-US)和blog post 博客。

规范
--

不属于任何规范，没有标准规范。

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

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

参见
--

* Components.stack
* 外部项目：TraceKit and javascript-stacktrace
* MSDN：error.stack docs
* Overview of the V8 JavaScript stack trace API