ES2017新特性,async,await等

原文连接:https://blog.csdn.net/sinat_17775997/article/details/76481923

async(异步) 函数变体

以下是已经存在的异步函数变体。请注意无处不在的 async 关键字。

  • 异步函数声明: async function foo() {}
  • 异步函数表达式: const foo = async function () {};
  • 异步函数定义:let obj = { async foo() {} }
  • 异步箭头函数: const foo = async () => {};

async(异步) 函数总是返回 Promises

async(异步) 函数的 Promise 完成状态:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. return 123;

  3. }

  4. asyncFunc()

  5. .then(x => console.log(x));

  6. // 123

</pre>

async(异步) 函数的 Promise 拒绝状态:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. throw new Error('Problem!');

  3. }

  4. asyncFunc()

  5. .catch(err => console.log(err));

  6. // Error: Problem!

</pre>

通过 await 处理 async(异步) 计算的结果和错误

await(只允许在 async(异步) 函数内部使用)等待其操作对象 Promise 返回:

  • 如果 Promise 是完成状态,await 的结果是完成态的值。
  • 如果 Promise 是拒绝状态,await 会抛出拒绝值。

处理单个 async(异步) 返回值:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. const result = await otherAsyncFunc();

  3. console.log(result);

  4. }

  5. // 等价于:

  6. function asyncFunc() {

  7. return otherAsyncFunc()

  8. .then(result => {

  9. console.log(result);

  10. });

  11. }

</pre>

按顺序处理多个 async(异步) 返回值:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. const result1 = await otherAsyncFunc1();

  3. console.log(result1);

  4. const result2 = await otherAsyncFunc2();

  5. console.log(result2);

  6. }

  7. // 等价于:

  8. function asyncFunc() {

  9. return otherAsyncFunc1()

  10. .then(result1 => {

  11. console.log(result1);

  12. return otherAsyncFunc2();

  13. })

  14. .then(result2 => {

  15. console.log(result2);

  16. });

  17. }

</pre>

并行处理多个 async(异步) 返回值:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. const [result1, result2] = await Promise.all([

  3. otherAsyncFunc1(),

  4. otherAsyncFunc2(),

  5. ]);

  6. console.log(result1, result2);

  7. }

  8. // 等价于:

  9. function asyncFunc() {

  10. return Promise.all([

  11. otherAsyncFunc1(),

  12. otherAsyncFunc2(),

  13. ])

  14. .then([result1, result2] => {

  15. console.log(result1, result2);

  16. });

  17. }

</pre>

错误处理:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. try {

  3. await otherAsyncFunc();

  4. } catch (err) {

  5. console.error(err);

  6. }

  7. }

  8. // 等价于:

  9. function asyncFunc() {

  10. return otherAsyncFunc()

  11. .catch(err => {

  12. console.error(err);

  13. });

  14. }

</pre>

理解 async(异步) 函数

在我解释 async(异步) 函数之前,我需要解释一下如何组合使用 Promises 和 Generator ,通过看起来同步的代码来执行 async(异步) 操作。

对于能够 async(异步) 计算其一次性结果的函数,作为 ES6 一部分的 Promises 已经变得流行起来。一个例子是 客户端 fetch API ,它是 XMLHttpRequest 获取数据的替代方法。使用示例如下:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. function fetchJson(url) {
  2. return fetch(url)
  3. .then(request => request.text())
  4. .then(text => {
  5. return JSON.parse(text);
  6. })
  7. .catch(error => {
  8. console.log(ERROR: ${error.stack});
  9. });
  10. }
  11. fetchJson('http://example.com/some_file.json')
  12. .then(obj => console.log(obj));

</pre>

通过 generator 来编写异步代码

co 是一个使用 Promise 和 generator 来实现看似同步编码的库,但与上一示例中使用的样式相同:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. const fetchJson = co.wrap(function* (url) {
  2. try {
  3. let request = yield fetch(url);
  4. let text = yield request.text();
  5. return JSON.parse(text);
  6. }
  7. catch (error) {
  8. console.log(ERROR: ${error.stack});
  9. }
  10. });

</pre>

每次回调函数( generator 函数)产生一个 Promise 对象给 co ,回调会被暂停,只有当 Promise 执行完成后,co 才会继续执行回调 。 如果 Promise 处于完成状态,yield 返回完成状态的值,如果处于拒绝状态,yield 抛出拒绝状态的错误。此外,co 保证结果是通过回调执行完成才返回的(类似于 then() 所做的工作)。

通过 async(异步) 函数来编写异步代码

async(异步) 函数用的特定语法基本上和 co 类似:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function fetchJson(url) {
  2. try {
  3. let request = await fetch(url);
  4. let text = await request.text();
  5. return JSON.parse(text);
  6. }
  7. catch (error) {
  8. console.log(ERROR: ${error.stack});
  9. }
  10. }

</pre>

在内部,异步函数写法更类似于 generators 。

以同步开始,异步处理的 async(异步) 函数

以下是 async(异步)函数是如何工作的:

  1. async(异步) 函数总是返回一个 Promise 对象 p 。Promise 对象在 async(异步) 函数开始执行时被创建。
  2. 函数体执行过程中,可以通过 returnthrow 终止执行。或者通过 await 暂停执行,在这种情况下,通常会在以后继续执行。
  3. 返回 Promise 对象 p

当执行 async(异步) 函数的函数体时,return x 中的 x 是 Promise 对象 p 的完成状态的结果,而 throw errp 的拒绝状态的结果。执行结果是异步返回的。换句话说:then()catch() 的回调总是在当前代码完成后执行。

以下是代码示例:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {

  2. console.log('asyncFunc()'); // (A)

  3. return 'abc';

  4. }

  5. asyncFunc().

  6. then(x => console.log(Resolved: ${x})); // (B)

  7. console.log('main'); // (C)

  8. // Output:

  9. // asyncFunc()

  10. // main

  11. // Resolved: abc

</pre>

您可以认为是以下的执行顺序:

  1. 行A:async(异步) 函数以同步开始。async(异步) 函数的 Promise 通过 return 来返回完成状态的结果。
  2. 行C:执行继续。
  3. 行B:Promise 完成状态通知是异步发生的。

返回不被包裹的 Promise 对象

Promise 的 resolve 是一项标准操作。 return 就是使用它来 resolve async(异步) 函数的 Promise p 的。这意味着:

  1. 返回一个非 Promise 值,该值将被处理成 p 的完成状态值。
  2. 返回一个 Promise 对象,那么 p 此时相当于是该 Promise 的状态。

因此,您可以返回一个 Promise ,并且这个 Promise 不会包裹在别的 Promise 中:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. return Promise.resolve(123);
  3. }
  4. asyncFunc()
  5. .then(x => console.log(x)) // 123

</pre>

有趣的是,返回一个拒绝状态(reject)的 Promise 对象会导致 async(异步) 函数被拒绝(reject)(通常,您可以使用 throw ):

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. return Promise.reject(new Error('Problem!'));
  3. }
  4. asyncFunc()
  5. .catch(err => console.error(err)); // Error: Problem!

</pre>

这与 Promise 解决方案的工作方式是一致的。 使你能够在不使用 await 的情况下,使用其他 async(异步) 计算来执行完成和拒绝处理:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. return anotherAsyncFunc();
  3. }

</pre>

上面的代码示例和下面的类似,但是比下面的更高效。(以下代码示例没有包裹 anotherAsyncFunc() 的 Promise ,而是包裹 anotherAsyncFunc() 本身 ):

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. return await anotherAsyncFunc();
  3. }

</pre>

使用 await 小贴士

不要忘记使用 await

在 async(异步) 函数中容易犯的一个错误就是在调用 async(异步) 函数时忘记使用 await

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. const value = otherAsyncFunc(); // missing await!
  3. ···
  4. }

</pre>

在这个例子中,方法执行返回的 Promise 对象赋值给了 value ,它通常不是你在 async(异步) 函数中想要的结果。

await 甚至可以在 async(异步) 函数不返回任何值的情况下起作用。它的 Promise 只是用来告诉调用者完成状态。例如:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function foo() {
  2. await step1(); // (A)
  3. ···
  4. }

</pre>

行A中的 await 确保在执行 foo() 剩余部分之前, step1() 已经执行完成。

不需要使用 await 的情况

有时,你只想触发异步计算,并且不需要关注它什么时候完成。以下是代码示例:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. const writer = openFile('someFile.txt');
  3. writer.write('hello'); // don’t wait
  4. writer.write('world'); // don’t wait
  5. await writer.close(); // wait for file to close
  6. }

</pre>

在这里,我们不关心单个的写入操作是否完成,只需要他们以正确的顺序执行 (API必须保证,但这是由 async(异步) 函数的执行模型所鼓励的,正如我们所见)。

asyncFunc() 函数最后一行的 await 确保该函数仅在文件写入关闭后才会执行。

由于返回的 Promises 没有被其他 async(异步) 函数包裹,所以你可以用 return 替换 await writer.close()

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function asyncFunc() {
  2. const writer = openFile('someFile.txt');
  3. writer.write('hello');
  4. writer.write('world');
  5. return writer.close();
  6. }

</pre>

这两个版本各有利弊,await 版本可能稍微更容易理解。

await 是顺序执行的,Promise.all() 是并行的

下面的代码调用了两个 async(异步) 函数, asyncFunc1()asyncFunc1()

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function foo() {
  2. const result1 = await asyncFunc1();
  3. const result2 = await asyncFunc2();
  4. }

</pre>

这两个函数调用顺序执行。但是并行执行它们往往会加快速度。您可以使用 Promise.all() :

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function foo() {
  2. const [result1, result2] = await Promise.all([
  3. asyncFunc1(),
  4. asyncFunc2(),
  5. ]);
  6. }

</pre>

我们现在正在等待一个包含两个元素的数组的 Promise ,而不是等待两个 Promise。

异步函数和回调

async(异步) 函数的一个限制是 await(等待) 只影响直接相关的 async(异步) 函数。因此,async(异步) 函数无法在回调(但是,回调可以是 async(异步) 函数本身,稍后我们将会看到)中使用 await(等待)。这使得基于回调的实用函数和方法难以使用。例子中我们将使用数组方法 map()forEach()

Array.prototype.map()

我们从数组方法 map() 开始讲解。在下面的代码示例中,我们想要加载由 URLs 数组指向的文件,并将它们返回到数组中。

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function downloadContent(urls) {
  2. return urls.map(url => {
  3. // 错误的语法!
  4. const content = await httpGet(url);
  5. return content;
  6. });
  7. }

</pre>

这不起作用,因为在正常箭头函数中 await 语法上是非法的(愚人码头注: await(等待) 只影响直接相关的 async(异步) 函数)。那么如何使用异步的箭头函数呢?

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function downloadContent(urls) {
  2. return urls.map(async (url) => { // 注意这一行中的 async ;
  3. const content = await httpGet(url);
  4. return content;
  5. });
  6. }

</pre>

这段代码有两个问题:

  • 现在返回的结果是一个 Promises 对象的数组,而不是一个字符串的数组。
  • 一旦 map() 执行完成,回调执行的工作并不能同时完成,因为 await 只暂停了包裹它的箭头函数 和 httpGet() 异步执行达到完成状态。这意味着你不能使用 await,来等待 downloadContent() 执行结束。

我们可以通过 Promise.all() 来解决这两个问题,Promise.all() 可以将一系列的 Promise 转换为一个 Promise 数组(所有值都是经过 Promise 完成并返回):

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function downloadContent(urls) {
  2. const promiseArray = urls.map(async (url) => {
  3. const content = await httpGet(url);
  4. return content;
  5. });
  6. return await Promise.all(promiseArray);
  7. }

</pre>

map() 的回调并不对 httpGet() 的结果起作用,只是起到不断执行的作用。因此,这里我们不需要一个异步的箭头函数,只需要一个普通的箭头函数就能达到相同的结果。

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function downloadContent(urls) {
  2. const promiseArray = urls.map(
  3. url => httpGet(url));
  4. return await Promise.all(promiseArray);
  5. }

</pre>

我们仍然可以做一个小的改进:这个异步函数稍微有点低效 – 首先通过 await 来解开 Promise.all() 的结果,然后通过 return 再次包裹它。 假设 return 不包裹 Promises,我们可以直接返回 Promise.all() 的结果:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function downloadContent(urls) {
  2. const promiseArray = urls.map(
  3. url => httpGet(url));
  4. return Promise.all(promiseArray);
  5. }

</pre>

Array.prototype.forEach()

我们使用数组的 forEach() 方法在控制台中打印几个通过 URLs 加载的文件的内容:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function logContent(urls) {
  2. urls.forEach(url => {
  3. // Wrong syntax
  4. const content = await httpGet(url);
  5. console.log(content);
  6. });
  7. }

</pre>

同样的,这里的代码会产生一个语法错误,因为你不能在通常的箭头函数内部使用 await

我们换作异步箭头函数:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function logContent(urls) {
  2. urls.forEach(async url => {
  3. const content = await httpGet(url);
  4. console.log(content);
  5. });
  6. // Not finished here
  7. }

</pre>

这段代码起作用了,但是会出现一个警告:httpGet() 返回的 Promise 对象是异步完成的,这也意味着当 forEach() 返回的时候回调可能还没有结束,因此你无法等到 logContent() 只能结束。

如果你并不想要这个结果,你可以将 forEach() 转换为 for-of 循环。

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function logContent(urls) {
  2. for (const url of urls) {
  3. const content = await httpGet(url);
  4. console.log(content);
  5. }
  6. }

</pre>

现在一切都在 for-of 循环完成后完成。但是,处理步骤依次发生:httpGet() 只是在第一次调用完成后再次调用。如果您希望处理步骤并行执行,你必须使用 Promise.all()

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function logContent(urls) {
  2. await Promise.all(urls.map(
  3. async url => {
  4. const content = await httpGet(url);
  5. console.log(content);
  6. }));
  7. }

</pre>

map() 用于创建一个 Promises 数组。 我们对他们的完成结果并不感兴趣,我们只要 await(等待) 所有方法执行完成。这意味着我们希望的是在 async(异步) 函数完成之后所有的执行都已经完成。我们也可以返回 Promise.all() ,但是该函数的结果是一个数组,其元素都是未完成状态的。

使用异步函数小贴士

了解你的 Promises

async(异步) 函数的基础就是 Promises 对象,这就是为什么理解 Promises 对于理解 async(异步) 函数至关重要。特别是当遇到不是基于 Promises 的老代码来实现 async(异步) 函数时,你通常别无选择,只能用 Promise 来重构。

举个例子,这里有个 “promisified” 版本的 XMLHttpRequest

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. function httpGet(url, responseType="") {
  2. return new Promise(
  3. function (resolve, reject) {
  4. const request = new XMLHttpRequest();
  5. request.onload = function () {
  6. if (this.status === 200) {
  7. // Success
  8. resolve(this.response);
  9. } else {
  10. // Something went wrong (404 etc.)
  11. reject(new Error(this.statusText));
  12. }
  13. };
  14. request.onerror = function () {
  15. reject(new Error(
  16. 'XMLHttpRequest Error: '+this.statusText));
  17. };
  18. request.open('GET', url);
  19. xhr.responseType = responseType;
  20. request.send();
  21. });
  22. }

</pre>

XMLHttpRequest 的 API 是基于回调的。通过一个 async(异步) 函数来实现它,意味着你必须在回调中返回 Promise 的完成(fulfill) 或拒绝(reject) 状态。这是不可能的,因为你只能通过 return 或者 throw 来完成这样的操作。你不能从回调函数内部 return 一个函数的结果。throw也有类似的约束。

因此,异步函数的通用编码风格是:

  • 直接使用 Promise 对象来构建异步原语。
  • 用异步函数来使用这些原语。

扩展阅读:“Exploring ES6” 中的 “异步编程中的 Promises 对象” 章节

立即调用异步函数表达式

有时,如果你可以在模块或脚本的顶层使用 await ,那将是一种很好的选择。当然,它只能在异步函数中使用。您可以创建一个异步函数 main() 并立即调用它:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function main() {
  2. console.log(await asyncFunction());
  3. }
  4. main();

</pre>

或者您可以使用立即调用异步函数表达式:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. (async function () {
  2. console.log(await asyncFunction());
  3. })();

</pre>

另一个选择是立即调用异步箭头函数:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. (async () => {
  2. console.log(await asyncFunction());
  3. })();

</pre>

用异步函数进行单元测试

以下代码使用 测试框架 mocha 对异步函数 asyncFun1() 和 asyncFun2() 来进行单元测试:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. import assert from 'assert';

  2. // Bug: the following test always succeeds

  3. test('Testing async code', function () {

  4. asyncFunc1() // (A)

  5. .then(result1 => {

  6. assert.strictEqual(result1, 'a'); // (B)

  7. return asyncFunc2();

  8. })

  9. .then(result2 => {

  10. assert.strictEqual(result2, 'b'); // (C)

  11. });

  12. });

</pre>

然而,这个测试总是成功的,因为 mocha 不会等待 B 行和 C 行断言执行完成。

你可以通过返回链式调用的 Promise 来解决这个问题,因为 mocha 会识别一个测试是否返回一个 Promise ,然后等待该 Promise 完成 再进行下一步(除非超时)。

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. return asyncFunc1() // (A)

</pre>

异步函数总是返回 Promises ,这使得它们能方便的、完美的来进行这种单元测试:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. import assert from 'assert';
  2. test('Testing async code', async function () {
  3. const result1 = await asyncFunc1();
  4. assert.strictEqual(result1, 'a');
  5. const result2 = await asyncFunc2();
  6. assert.strictEqual(result2, 'b');
  7. });

</pre>

在 mocha 中使用异步单元测试异步函数有两个优点:代码更简洁,能够准确处理返回的 Promise 对象。

不要担心没有处理的拒绝拒态

当前的 JavaScript 引擎可以在拒绝态未处理的情况下提出警告。以下代码在过去会经常执行失败,但是当前的 JavaScript 引擎可以进行警告:

<pre class="prettyprint lang-JavaScript linenums:1 prettyprinted" name="code" style="box-sizing: border-box; outline: 0px; padding: 0px; margin: 20px 0px; position: relative; overflow: hidden; white-space: pre-wrap; word-wrap: break-word; font-family: "courier new"; font-size: 14px; line-height: 20px; color: rgb(102, 102, 102); word-break: break-all; background: rgb(68, 68, 68); border: 1px solid rgb(39, 40, 34); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; vertical-align: baseline; max-width: 100%;">

JavaScript 代码:
  1. async function foo() {
  2. throw new Error('Problem!');
  3. }
  4. foo();

</pre>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 月集村、柳沟村、刘庄村,三个村庄几乎呈等边三角形,分布在与山东交界的一片广袤的土地上,这里地广人稀,人均土地二亩多...
    始行者阅读 155评论 0 0
  • 践行第10天2017.29 城市:宜兴 姓名:糖糖 一、[设定目标(3件帮助人的好事)]: 1.转发正能量善知识链...
    爱阳光的TT阅读 217评论 0 0