es6_06_Promise_async

ES6_学习笔记_Part_06



Promise 对象

Promise 的含义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。


从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。

Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。


Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,

有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。


(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。

Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。

如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

注意,为了行文方便,本章后面的resolved统一只指fulfilled状态,不包含rejected状态。


有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

此外,Promise对象提供统一的接口,使得控制异步操作更加容易。


Promise也有一些缺点。

首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。

第二,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。

基本用法

ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。

下面代码创造了一个Promise实例。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject

它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;


reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受两个回调函数作为参数。

第一个回调函数是Promise对象的状态变为resolved时调用,

第二个回调函数是Promise对象的状态变为rejected时调用。

其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

下面是一个Promise对象的简单例子。

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。

过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数。

Promise 新建后就会立即执行。

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise

然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

下面是异步加载图片的例子。

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

上面代码中,使用Promise包装了一个图片加载的异步操作。

如果加载成功,就调用resolve方法,否则就调用reject方法。

下面是一个用Promise对象实现的 Ajax 操作的例子。

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

上面代码中,

getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。

需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。

reject函数的参数通常是Error对象的实例,表示抛出的错误;

resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,

比如像下面这样。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})

上面代码中,p1p2都是 Promise 的实例,但是p2resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。

如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;

如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

上面代码中,p1是一个 Promise,3 秒之后变为rejected

p2的状态在 1 秒之后改变,resolve方法返回的是p1

由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。

所以,后面的then语句都变成针对后者(p1)。

又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

注意,调用resolvereject并不会终结 Promise 的参数函数的执行。

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1

上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。

这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

一般来说,调用resolvereject以后,Promise 的使命就完成了,

后继操作应该放到then方法里面,而不应该直接写在resolvereject的后面。

所以,最好在它们前面加上return语句,这样就不会有意外。

new Promise((resolve, reject) => {
  return resolve(1);
  // 后面的语句不会执行
  console.log(2);
})

Promise.prototype.then()

Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。

它的作用是为 Promise 实例添加状态改变时的回调函数。

前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。

因此可以采用链式写法,即then方法后面再调用另一个then方法。

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

上面的代码使用then方法,依次指定了两个回调函数。

第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

采用链式的then,可以指定一组按照次序调用的回调函数。

这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),

这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("resolved: ", comments);
}, function funcB(err){
  console.log("rejected: ", err);
});

上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。

这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。

如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB

如果采用箭头函数,上面的代码可以写得更简洁。

getJSON("/post/1.json").then(
  post => getJSON(post.commentURL)
).then(
  comments => console.log("resolved: ", comments),
  err => console.log("rejected: ", err)
);

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

上面代码中,getJSON方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then方法指定的回调函数;

如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。

另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

下面是一个例子。

const promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
// Error: test

上面代码中,promise抛出一个错误,就被catch方法指定的回调函数捕获。

注意,上面的写法与下面两种写法是等价的。

// 写法一
const promise = new Promise(function(resolve, reject) {
  try {
    throw new Error('test');
  } catch(e) {
    reject(e);
  }
});
promise.catch(function(error) {
  console.log(error);
});

// 写法二
const promise = new Promise(function(resolve, reject) {
  reject(new Error('test'));
});
promise.catch(function(error) {
  console.log(error);
});

比较上面两种写法,可以发现reject方法的作用,等同于抛出错误。

如果 Promise 状态已经变成resolved,再抛出错误是无效的。

const promise = new Promise(function(resolve, reject) {
  resolve('ok');
  throw new Error('test');
});
promise
  .then(function(value) { console.log(value) })
  .catch(function(error) { console.log(error) });
// ok

上面代码中,Promise 在resolve语句后面,再抛出错误,不会被捕获,等于没有抛出。

因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。

也就是说,错误总是会被下一个catch语句捕获。

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前面三个Promise产生的错误
});

上面代码中,一共有三个 Promise 对象:一个由getJSON产生,两个由then产生。

它们之中任何一个抛出的错误,都会被最后一个catch捕获。

一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// good
promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
  });

上面代码中,第二种写法要好于第一种写法,

理由是第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch)。

因此,建议总是使用catch方法,而不使用then方法的第二个参数。

跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};

someAsyncThing().then(function() {
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123

上面代码中,someAsyncThing函数产生的 Promise 对象,内部有语法错误。

浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined

但是不会退出进程、终止脚本执行,2 秒之后还是会输出123

这就是说,Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

这个脚本放在服务器执行,退出码就是0(即表示执行成功)。


不过,Node 有一个unhandledRejection事件,专门监听未捕获的reject错误,

上面的脚本会触发这个事件的监听函数,可以在监听函数里面抛出错误。

process.on('unhandledRejection', function (err, p) {
  throw err;
});

上面代码中,unhandledRejection事件的监听函数有两个参数,第一个是错误对象,

第二个是报错的 Promise 实例,它可以用来了解发生错误的环境信息。

注意,Node 有计划在未来废除unhandledRejection事件。

如果 Promise 内部有未捕获的错误,会直接终止进程,并且进程的退出码不为 0。

再看下面的例子。

const promise = new Promise(function (resolve, reject) {
  resolve('ok');
  setTimeout(function () { throw new Error('test') }, 0)
});
promise.then(function (value) { console.log(value) });
// ok
// Uncaught Error: test

上面代码中,Promise 指定在下一轮“事件循环”再抛出错误。

到了那个时候,Promise 的运行已经结束了,所以这个错误是在 Promise 函数体外抛出的,会冒泡到最外层,成了未捕获的错误。

一般总是建议,Promise 对象后面要跟catch方法,这样可以处理 Promise 内部发生的错误。

catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};

someAsyncThing()
.catch(function(error) {
  console.log('oh no', error);
})
.then(function() {
  console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on

上面代码运行完catch方法指定的回调函数,会接着运行后面那个then方法指定的回调函数。

如果没有报错,则会跳过catch方法。

Promise.resolve()
.catch(function(error) {
  console.log('oh no', error);
})
.then(function() {
  console.log('carry on');
});
// carry on

上面的代码因为没有报错,跳过了catch方法,直接执行后面的then方法。

此时,要是then方法里面报错,就与前面的catch无关了。

catch方法之中,还能再抛出错误。

const someAsyncThing = function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};

someAsyncThing().then(function() {
  return someOtherAsyncThing();
}).catch(function(error) {
  console.log('oh no', error);
  // 下面一行会报错,因为 y 没有声明
  y + 2;
}).then(function() {
  console.log('carry on');
});
// oh no [ReferenceError: x is not defined]

上面代码中,catch方法抛出一个错误,因为后面没有别的catch方法了,导致这个错误不会被捕获,也不会传递到外层。

如果改写一下,结果就不一样了。

someAsyncThing().then(function() {
  return someOtherAsyncThing();
}).catch(function(error) {
  console.log('oh no', error);
  // 下面一行会报错,因为y没有声明
  y + 2;
}).catch(function(error) {
  console.log('carry on', error);
});
// oh no [ReferenceError: x is not defined]
// carry on [ReferenceError: y is not defined]

上面代码中,第二个catch方法用来捕获前一个catch方法抛出的错误。

Promise.prototype.finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

该方法是 ES2018 引入标准的。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

上面代码中,不管promise最后的状态,在执行完thencatch指定的回调函数以后,都会执行finally方法指定的回调函数。

下面是一个例子,服务器使用 Promise 处理请求,然后使用finally方法关掉服务器。

server.listen(port)
  .then(function () {
    // ...
  })
  .finally(server.stop);

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected

这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。

finally本质上是then方法的特例。

promise
.finally(() => {
  // 语句
});

// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);

上面代码中,如果不使用finally方法,同样的语句需要为成功和失败两种情况各写一次。

有了finally方法,则只需要写一次。

它的实现也很简单。

Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

上面代码中,不管前面的 Promise 是fulfilled还是rejected,都会执行回调函数callback

从上面的实现还可以看到,finally方法总是会返回原来的值。

// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})

// resolve 的值是 2
Promise.resolve(2).finally(() => {})

// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})

// reject 的值是 3
Promise.reject(3).finally(() => {})

Promise.all()

Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

上面代码中,Promise.all方法接受一个数组作为参数,p1p2p3都是 Promise 实例,

如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。

Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。


(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

下面是一个具体的例子。

// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

上面代码中,promises是包含 6 个 Promise 实例的数组,只有这 6 个实例的状态都变成fulfilled,或者其中有一个变为rejected

才会调用Promise.all方法后面的回调函数。

下面是另一个例子。

const databasePromise = connectDatabase();

const booksPromise = databasePromise
  .then(findAllBooks);

const userPromise = databasePromise
  .then(getCurrentUser);

Promise.all([
  booksPromise,
  userPromise
])
.then(([books, user]) => pickTopRecommentations(books, user));

上面代码中,booksPromiseuserPromise是两个异步操作,只有等到它们的结果都返回了,

才会触发pickTopRecommentations这个回调函数。

注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

上面代码中,p1resolvedp2首先会rejected

但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。

该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved

因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。

如果p2没有自己的catch方法,就会调用Promise.all()catch方法。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了

Promise.race()

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。

那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。

下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve

const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);

上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。

Promise.resolve()

有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。

const jsPromise = Promise.resolve($.ajax('/whatever.json'));

上面代码将 jQuery 生成的deferred对象,转为一个新的 Promise 对象。

Promise.resolve等价于下面的写法。

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

Promise.resolve方法的参数分成四种情况。

(1)参数是一个 Promise 实例

如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

(2)参数是一个thenable对象

thenable对象指的是具有then方法的对象,比如下面这个对象。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};

let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。

(3)参数不是具有then方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved

const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello

上面代码生成一个新的 Promise 对象的实例p

由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),

返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。

Promise.resolve方法的参数,会同时传给回调函数。

(4)不带有任何参数

Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve方法。

const p = Promise.resolve();

p.then(function () {
  // ...
});

上面代码的变量p就是一个 Promise 对象。

需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

Promise.reject()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) {
  console.log(s)
});
// 出错了

上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。

注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。

这一点与Promise.resolve方法不一致。

const thenable = {
  then(resolve, reject) {
    reject('出错了');
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable)
})
// true

上面代码中,Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。

应用

加载图片

我们可以将图片的加载写成一个Promise,一旦加载完成,Promise的状态就发生变化。

const preloadImage = function (path) {
  return new Promise(function (resolve, reject) {
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};

Generator 函数与 Promise 的结合

使用 Generator 函数管理流程,遇到异步操作的时候,通常返回一个Promise对象。

function getFoo () {
  return new Promise(function (resolve, reject){
    resolve('foo');
  });
}

const g = function* () {
  try {
    const foo = yield getFoo();
    console.log(foo);
  } catch (e) {
    console.log(e);
  }
};

function run (generator) {
  const it = generator();

  function go(result) {
    if (result.done) return result.value;

    return result.value.then(function (value) {
      return go(it.next(value));
    }, function (error) {
      return go(it.throw(error));
    });
  }

  go(it.next());
}

run(g);

上面代码的 Generator 函数g之中,有一个异步操作getFoo,它返回的就是一个Promise对象。

函数run用来处理这个Promise对象,并调用下一个next方法。

Promise.try()

实际开发中,经常遇到一种情况:不知道或者不想区分,函数f是同步函数还是异步操作,但是想用 Promise 来处理它。

因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理f抛出的错误。

一般就会采用下面的写法。

Promise.resolve().then(f)

上面的写法有一个缺点,就是如果f是同步函数,那么它会在本轮事件循环的末尾执行。

const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now

上面代码中,函数f是同步的,但是用 Promise 包装了以后,就变成异步执行了。

那么有没有一种方法,让同步函数同步执行,异步函数异步执行,并且让它们具有统一的 API 呢?

回答是可以的,并且还有两种写法。第一种写法是用async函数来写。

const f = () => console.log('now');
(async () => f())();
console.log('next');
// now
// next

上面代码中,第二行是一个立即执行的匿名函数,会立即执行里面的async函数,

因此如果f是同步的,就会得到同步的结果;如果f是异步的,就可以用then指定下一步,

就像下面的写法。

(async () => f())()
.then(...)

需要注意的是,async () => f()会吃掉f()抛出的错误。所以,如果想捕获错误,要使用promise.catch方法。

(async () => f())()
.then(...)
.catch(...)

第二种写法是使用new Promise()

const f = () => console.log('now');
(
  () => new Promise(
    resolve => resolve(f())
  )
)();
console.log('next');
// now
// next

上面代码也是使用立即执行的匿名函数,执行new Promise()。这种情况下,同步函数也是同步执行的。

鉴于这是一个很常见的需求,所以现在有一个提案,提供Promise.try方法替代上面的写法。

const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next

事实上,Promise.try存在已久,Promise 库BluebirdQwhen,早就提供了这个方法。

由于Promise.try为所有操作提供了统一的处理机制,所以如果想用then方法管理流程,最好都用Promise.try包装一下。

这样有许多好处,其中一点就是可以更好地管理异常。

function getUsername(userId) {
  return database.users.get({id: userId})
  .then(function(user) {
    return user.name;
  });
}

上面代码中,database.users.get()返回一个 Promise 对象,如果抛出异步错误,可以用catch方法捕获,就像下面这样写。

database.users.get({id: userId})
.then(...)
.catch(...)

但是database.users.get()可能还会抛出同步错误(比如数据库连接错误,具体要看实现方法),这时你就不得不用try...catch去捕获。

try {
  database.users.get({id: userId})
  .then(...)
  .catch(...)
} catch (e) {
  // ...
}

上面这样的写法就很笨拙了,这时就可以统一用promise.catch()捕获所有同步和异步的错误。

Promise.try(database.users.get({id: userId}))
  .then(...)
  .catch(...)

事实上,Promise.try就是模拟try代码块,就像promise.catch模拟的是catch代码块。







async 函数

含义

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它就是 Generator 函数的语法糖。

前文有一个 Generator 函数,依次读取两个文件。

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

写成async函数,就是下面这样。

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

async函数对 Generator 函数的改进,体现在以下四点。

(1)内置执行器。

Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。

也就是说,async函数的执行,与普通函数一模一样,只要一行。

asyncReadFile();

上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。

这完全不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

(2)更好的语义。

asyncawait,比起星号和yield,语义更清楚了。

async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。

co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,

async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

(4)返回值是 Promise。

async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。

你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

基本用法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。

当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

下面是一个例子。

async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName('goog').then(function (result) {
  console.log(result);
});

上面代码是一个获取股票报价的函数,函数前面的async关键字,表明该函数内部有异步操作。

调用该函数时,会立即返回一个Promise对象。

下面是另一个例子,指定多少毫秒后输出一个值。

function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

上面代码指定 50 毫秒以后,输出hello world

由于async函数返回的是 Promise 对象,可以作为await命令的参数。

所以,上面的例子也可以写成下面的形式。

async function timeout(ms) {
  await new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

async 函数有多种使用形式。

// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

const storage = new Storage();
storage.getAvatar('jake').then();

// 箭头函数
const foo = async () => {};

语法

async函数的语法规则总体上比较简单,难点是错误处理机制。

返回 Promise 对象

async函数返回一个 Promise 对象。

async函数内部return语句返回的值,会成为then方法回调函数的参数。

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

上面代码中,函数f内部return命令返回的值,会被then方法回调函数接收到。

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。

抛出的错误对象会被catch方法回调函数接收到。

async function f() {
  throw new Error('出错了');
}

f().then(
  v => console.log(v),
  e => console.log(e)
)
// Error: 出错了

Promise 对象的状态变化

async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。

也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

下面是一个例子。

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/([\s\S]+)<\/title>/i</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token number" style="color:rgb(174,129,255);">1</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token function">getTitle<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'https://tc39.github.io/ecma262/'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>console<span class="token punctuation" style="color:rgb(248,248,242);">.</span>log<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token comment" style="color:rgb(117,113,94);">
// "ECMAScript 2017 Language Specification"
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,函数<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getTitle</code>内部有三个操作:抓取网页、取出文本、匹配页面标题。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">只有这三个操作全部完成,才会执行<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">then</code>方法里面的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">console.log</code>。</p> 
  <h3 class="await-命令" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">await 命令</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">正常情况下,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令后面是一个 Promise 对象。如果不是,会被转成一个立即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolve</code>的 Promise 对象。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> await <span class="token number" style="color:rgb(174,129,255);">123</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token comment" style="color:rgb(117,113,94);">
// 123
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令的参数是数值<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">123</code>,它被转成 Promise 对象,并立即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolve</code>。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令后面的 Promise 对象如果变为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>状态,则<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>的参数会被<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>方法的回调函数接收到。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">reject<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'出错了'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token comment" style="color:rgb(117,113,94);">
// 出错了
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">注意,上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>语句前面没有<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">return</code>,但是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>方法的参数依然传入了<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>方法的回调函数。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这里如果在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>前面加上<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">return</code>,效果是一样的。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">只要一个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>语句后面的 Promise 变为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>,那么整个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数都会中断执行。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">reject<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'出错了'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'hello world'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // 不会执行
</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,第二个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>语句是不会执行的,因为第一个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>语句状态变成了<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这时可以将第一个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>放在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">try...catch</code>结构里面,这样不管这个异步操作是否成功,第二个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>都会执行。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">reject<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'出错了'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'hello world'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token comment" style="color:rgb(117,113,94);">
// hello world
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">另一种方法是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>后面的 Promise 对象再跟一个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>方法,处理前面可能出现的错误。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">reject<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'出错了'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'hello world'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token comment" style="color:rgb(117,113,94);">
// 出错了
</span><span class="token comment" style="color:rgb(117,113,94);">// hello world
</span></code></code></pre> 
  <h3 class="错误处理" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">错误处理</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>后面的异步操作出错,那么等同于<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数返回的 Promise 对象被<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  await <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Promise</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>resolve<span class="token punctuation" style="color:rgb(248,248,242);">,</span> reject<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">throw</span> <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Error</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token string">'出错了'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token comment" style="color:rgb(117,113,94);">
// Error:出错了
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">f</code>执行后,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>后面的 Promise 对象会抛出一个错误对象,导致<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>方法的回调函数被调用,它的参数就是抛出的错误对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">具体的执行机制,可以参考后文的“async 函数的实现原理”。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">防止出错的方法,也是将其放在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">try...catch</code>代码块之中。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Promise</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>resolve<span class="token punctuation" style="color:rgb(248,248,242);">,</span> reject<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      <span class="token keyword" style="color:rgb(102,217,239);">throw</span> <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Error</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token string">'出错了'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">await<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'hello world'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果有多个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令,可以统一放在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">try...catch</code>结构中。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">main<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const val1 <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">firstStep<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    const val2 <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">secondStep<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>val1<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    const val3 <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">thirdStep<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>val1<span class="token punctuation" style="color:rgb(248,248,242);">,</span> val2<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'Final: '</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> val3<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token keyword" style="color:rgb(102,217,239);">catch</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token class-name">err</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">error<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>err<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面的例子使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">try...catch</code>结构,实现多次重复尝试。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">const superagent <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">require<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'superagent'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
const NUM_RETRIES <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token number" style="color:rgb(174,129,255);">3</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">test<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> i<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>i <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token number" style="color:rgb(174,129,255);">0</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span> i <span class="token operator" style="color:rgb(249,38,114);"><</span> NUM_RETRIES<span class="token punctuation" style="color:rgb(248,248,242);">;</span> <span class="token operator" style="color:rgb(249,38,114);">++</span>i<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      await superagent<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">get</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token string">'http://google.com/this-throws-an-error'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token keyword" style="color:rgb(102,217,239);">break</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>err<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>i<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // 3
</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">test<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,如果<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>操作成功,就会使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">break</code>语句退出循环;如果失败,会被<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>语句捕捉,然后进入下一轮循环。</p> 
  <h3 class="使用注意点" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">使用注意点</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">第一点,前面已经说过,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令后面的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Promise</code>对象,运行结果可能是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">rejected</code>,所以最好把<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令放在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">try...catch</code>代码块中。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">myFunction<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await <span class="token function">somethingThatReturnsAPromise<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token class-name">err</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>err<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 另一种写法
</span>
async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">myFunction<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  await <span class="token function">somethingThatReturnsAPromise<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>err<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>err<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">第二点,多个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">let</span> foo <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">getFoo<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token keyword" style="color:rgb(102,217,239);">let</span> bar <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">getBar<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getFoo</code>和<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getBar</code>是两个独立的异步操作(即互不依赖),被写成继发关系。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这样比较耗时,因为只有<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getFoo</code>完成以后,才会执行<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getBar</code>,完全可以让它们同时触发。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token comment" style="color:rgb(117,113,94);">// 写法一
</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span>foo<span class="token punctuation" style="color:rgb(248,248,242);">,</span> bar<span class="token punctuation" style="color:rgb(248,248,242);">]</span> <span class="token operator" style="color:rgb(249,38,114);">=</span> await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">all<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token function">getFoo<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token function">getBar<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 写法二
</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> fooPromise <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">getFoo<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token keyword" style="color:rgb(102,217,239);">let</span> barPromise <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">getBar<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token keyword" style="color:rgb(102,217,239);">let</span> foo <span class="token operator" style="color:rgb(249,38,114);">=</span> await fooPromise<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token keyword" style="color:rgb(102,217,239);">let</span> bar <span class="token operator" style="color:rgb(249,38,114);">=</span> await barPromise<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面两种写法,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getFoo</code>和<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">getBar</code>都是同时触发,这样就会缩短程序的执行时间。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">第三点,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令只能用在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数之中,如果用在普通函数,就会报错。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">dbFuc<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>db<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> docs <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 报错
</span>  docs<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">forEach<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await db<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">post<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码会报错,因为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>用在普通函数之中了。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">但是,如果将<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">forEach</code>方法的参数改成<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数,也有问题。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">dbFuc<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>db<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token comment" style="color:rgb(117,113,94);"> //这里不需要 async
</span>  <span class="token keyword" style="color:rgb(102,217,239);">let</span> docs <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 可能得到错误结果
</span>  docs<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">forEach<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await db<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">post<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码可能不会正常工作,原因是这时三个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">db.post</code>操作将是并发执行,也就是同时执行,而不是继发执行。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">正确的写法是采用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for</code>循环。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">dbFuc<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>db<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> docs <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> doc of docs<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await db<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">post<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果确实希望多个请求并发执行,可以使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Promise.all</code>方法。当三个请求都会<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolved</code>时,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面两种写法效果相同。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">dbFuc<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>db<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> docs <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> promises <span class="token operator" style="color:rgb(249,38,114);">=</span> docs<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">map<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> db<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">post<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

  <span class="token keyword" style="color:rgb(102,217,239);">let</span> results <span class="token operator" style="color:rgb(249,38,114);">=</span> await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">all<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>promises<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>results<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 或者使用下面的写法
</span>
async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">dbFuc<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>db<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> docs <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> promises <span class="token operator" style="color:rgb(249,38,114);">=</span> docs<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">map<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> db<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">post<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>doc<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

  <span class="token keyword" style="color:rgb(102,217,239);">let</span> results <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> promise of promises<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    results<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">push<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await promise<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>results<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">目前,<code style="color:rgb(70,130,190);font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">@std/esm</code><span style="color:#4682be;"><span>模块加载器支持顶层</span></span><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>,即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令可以不放在 async 函数里面,直接使用。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token comment" style="color:rgb(117,113,94);">// async 函数的写法
</span>const start <span class="token operator" style="color:rgb(249,38,114);">=</span> async <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const res <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">fetch<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'google.com'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> res<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

<span class="token function">start<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>console<span class="token punctuation" style="color:rgb(248,248,242);">.</span>log<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 顶层 await 的写法
</span>const res <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">fetch<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'google.com'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await res<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,第二种写法的脚本必须使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">@std/esm</code>加载器,才会生效。</p> 
  <h2 class="async-函数的实现原理" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;font-size:18px;text-align:left;border-top:2px solid rgb(102,102,102);color:rgb(51,51,51);font-family:Verdana, Arial;">async 函数的实现原理</h2> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">fn<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>args<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // ...
</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 等同于
</span>
<span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">fn<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>args<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">spawn<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
   <span class="token comment" style="color:rgb(117,113,94);"> // ...
</span>  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">所有的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数都可以写成上面的第二种形式,其中的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">spawn</code>函数就是自动执行器。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面给出<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">spawn</code>函数的实现,基本就是前文自动执行器的翻版。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">spawn<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>genF<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Promise</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>resolve<span class="token punctuation" style="color:rgb(248,248,242);">,</span> reject<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const gen <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">genF<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">step<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>nextF<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      <span class="token keyword" style="color:rgb(102,217,239);">let</span> next<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
        next <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">nextF<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
        <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">reject<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
      <span class="token keyword" style="color:rgb(102,217,239);">if</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>next<span class="token punctuation" style="color:rgb(248,248,242);">.</span>done<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
        <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>next<span class="token punctuation" style="color:rgb(248,248,242);">.</span>value<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
      Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>next<span class="token punctuation" style="color:rgb(248,248,242);">.</span>value<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
        <span class="token function">step<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span> <span class="token keyword" style="color:rgb(102,217,239);">return</span> gen<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span> <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
        <span class="token function">step<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span> <span class="token keyword" style="color:rgb(102,217,239);">return</span> gen<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">throw</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span> <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
    <span class="token function">step<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span> <span class="token keyword" style="color:rgb(102,217,239);">return</span> gen<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>undefined<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span> <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <h2 class="与其他异步处理方法的比较" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;font-size:18px;text-align:left;border-top:2px solid rgb(102,102,102);color:rgb(51,51,51);font-family:Verdana, Arial;">与其他异步处理方法的比较</h2> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">我们通过一个例子,来看 async 函数与 Promise、Generator 函数的比较。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">假定某个 DOM 元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">首先是 Promise 的写法。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">chainAnimationsPromise<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>elem<span class="token punctuation" style="color:rgb(248,248,242);">,</span> animations<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 变量ret用来保存上一个动画的返回值
</span>  <span class="token keyword" style="color:rgb(102,217,239);">let</span> ret <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token keyword" style="color:rgb(102,217,239);">null</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 新建一个空的Promise
</span>  <span class="token keyword" style="color:rgb(102,217,239);">let</span> p <span class="token operator" style="color:rgb(249,38,114);">=</span> Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 使用then方法,添加所有动画
</span>  <span class="token keyword" style="color:rgb(102,217,239);">for</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> anim of animations<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    p <span class="token operator" style="color:rgb(249,38,114);">=</span> p<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>val<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      ret <span class="token operator" style="color:rgb(249,38,114);">=</span> val<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">anim<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>elem<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 返回一个部署了错误捕捉机制的Promise
</span>  <span class="token keyword" style="color:rgb(102,217,239);">return</span> p<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token comment" style="color:rgb(117,113,94);">/* 忽略错误,继续执行 */</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">return</span> ret<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">虽然 Promise 的写法比回调函数的写法大大改进,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">但是一眼看上去,代码完全都是 Promise 的 API(<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">then</code>、<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>等等),操作本身的语义反而不容易看出来。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">接着是 Generator 函数的写法。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">chainAnimationsGenerator<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>elem<span class="token punctuation" style="color:rgb(248,248,242);">,</span> animations<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>

  <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">spawn<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">let</span> ret <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token keyword" style="color:rgb(102,217,239);">null</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      <span class="token keyword" style="color:rgb(102,217,239);">for</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> anim of animations<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
        ret <span class="token operator" style="color:rgb(249,38,114);">=</span> yield <span class="token function">anim<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>elem<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      <span class="token comment" style="color:rgb(117,113,94);">/* 忽略错误,继续执行 */</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
    <span class="token keyword" style="color:rgb(102,217,239);">return</span> ret<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码使用 Generator 函数遍历了每个动画,语义比 Promise 写法更清晰,用户定义的操作全部都出现在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">spawn</code>函数的内部。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这个写法的问题在于,必须有一个任务运行器,自动执行 Generator 函数,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">spawn</code>函数就是自动执行器,它返回一个 Promise 对象,而且必须保证<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>语句后面的表达式,必须返回一个 Promise。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">最后是 async 函数的写法。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">chainAnimationsAsync<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>elem<span class="token punctuation" style="color:rgb(248,248,242);">,</span> animations<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> ret <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token keyword" style="color:rgb(102,217,239);">null</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">for</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token keyword" style="color:rgb(102,217,239);">let</span> anim of animations<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      ret <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">anim<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>elem<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token comment" style="color:rgb(117,113,94);">/* 忽略错误,继续执行 */</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> ret<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">可以看到 Async 函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">它将 Generator 写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果使用 Generator 写法,自动执行器需要用户自己提供。</p> 
  <h2 class="实例:按顺序完成异步操作" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;font-size:18px;text-align:left;border-top:2px solid rgb(102,102,102);color:rgb(51,51,51);font-family:Verdana, Arial;">实例:按顺序完成异步操作</h2> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">实际开发中,经常遇到一组异步操作,需要按照顺序完成。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">比如,依次远程读取一组 URL,然后按照读取的顺序输出结果。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">Promise 的写法如下。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">logInOrder<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>urls<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // 远程读取所有URL
</span>  const textPromises <span class="token operator" style="color:rgb(249,38,114);">=</span> urls<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">map<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>url <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">fetch<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>url<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>response <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> response<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 按次序输出
</span>  textPromises<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">reduce<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>chain<span class="token punctuation" style="color:rgb(248,248,242);">,</span> textPromise<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">return</span> chain<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> textPromise<span class="token punctuation" style="color:rgb(248,248,242);">)</span>
      <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>text <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>text<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">fetch</code>方法,同时远程读取一组 URL。每个<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">fetch</code>操作都返回一个 Promise 对象,放入<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">textPromises</code>数组。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">然后,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reduce</code>方法依次处理每个 Promise 对象,然后使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">then</code>,将所有 Promise 对象连起来,因此就可以依次输出结果。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这种写法不太直观,可读性比较差。下面是 async 函数实现。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">logInOrder<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>urls<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const url of urls<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const response <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">fetch<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>url<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await response<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码确实大大简化,问题是所有远程操作都是继发。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">只有前一个 URL 返回结果,才会去读取下一个 URL,这样做效率很差,非常浪费时间。我们需要的是并发发出远程请求。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">logInOrder<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>urls<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // 并发读取远程URL
</span>  const textPromises <span class="token operator" style="color:rgb(249,38,114);">=</span> urls<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">map<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>async url <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const response <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">fetch<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>url<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token keyword" style="color:rgb(102,217,239);">return</span> response<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

 <span class="token comment" style="color:rgb(117,113,94);"> // 按次序输出
</span>  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const textPromise of textPromises<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await textPromise<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,虽然<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">map</code>方法的参数是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数,但它是并发执行的,因为只有<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数内部是继发执行,外部不受影响。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">后面的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for..of</code>循环内部使用了<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>,因此实现了按顺序输出。</p> 
  <h2 class="异步遍历器" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;font-size:18px;text-align:left;border-top:2px solid rgb(102,102,102);color:rgb(51,51,51);font-family:Verdana, Arial;">异步遍历器</h2> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">《遍历器》一章说过,Iterator 接口是一种数据遍历的协议,只要调用遍历器对象的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,就会得到一个对象,表示当前遍历指针所在的那个位置的信息。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法返回的对象的结构是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">{value, done}</code>,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">其中<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code>表示当前的数据的值,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code>是一个布尔值,表示遍历是否结束。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这里隐含着一个规定,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法必须是同步的,只要调用就必须立刻返回值。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">也就是说,一旦执行<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,就必须同步地得到<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code>和<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code>这两个属性。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果遍历指针正好指向同步操作,当然没有问题,但对于异步操作,就不太合适了。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">目前的解决方法是,Generator 函数里面的异步操作,返回一个 Thunk 函数或者 Promise 对象,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code>属性是一个 Thunk 函数或者 Promise 对象,等待以后返回真正的值,而<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code>属性则还是同步产生的。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">ES2018 <span style="color:#4682be;"><span>引入</span></span>了”异步遍历器“(Async Iterator),为异步操作提供原生的遍历器接口,即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code>和<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code>这两个属性都是异步产生。</p> 
  <h3 class="异步遍历的接口" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">异步遍历的接口</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步遍历器的最大的语法特点,就是调用遍历器的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,返回的是一个 Promise 对象。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">asyncIterator
  <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>
    <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span> value<span class="token punctuation" style="color:rgb(248,248,242);">,</span> done <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token comment" style="color:rgb(117,113,94);">/* ... */</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">asyncIterator</code>是一个异步遍历器,调用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法以后,返回一个 Promise 对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">因此,可以使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">then</code>方法指定,这个 Promise 对象的状态变为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolve</code>以后的回调函数。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">回调函数的参数,则是一个具有<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code>和<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code>两个属性的对象,这个跟同步遍历器是一样的。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">我们知道,一个对象的同步遍历器的接口,部署在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Symbol.iterator</code>属性上面。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">同样地,对象的异步遍历器接口,部署在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Symbol.asyncIterator</code>属性上面。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">不管是什么样的对象,只要它的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Symbol.asyncIterator</code>属性有值,就表示应该对它进行异步遍历。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面是一个异步遍历器的例子。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">const asyncIterable <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">createAsyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
const asyncIterator <span class="token operator" style="color:rgb(249,38,114);">=</span> asyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">[</span>Symbol<span class="token punctuation" style="color:rgb(248,248,242);">.</span>asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

asyncIterator
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterResult1 <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterResult1<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // { value: 'a', done: false }
</span>  <span class="token keyword" style="color:rgb(102,217,239);">return</span> asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterResult2 <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterResult2<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // { value: 'b', done: false }
</span>  <span class="token keyword" style="color:rgb(102,217,239);">return</span> asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterResult3 <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterResult3<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // { value: undefined, done: true }
</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,异步遍历器其实返回了两次值。第一次调用的时候,返回一个 Promise 对象;</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">等到 Promise 对象<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolve</code>了,再返回一个表示当前数据成员信息的对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这就是说,异步遍历器与同步遍历器最终行为是一致的,只是会先返回 Promise 对象,作为中介。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">由于异步遍历器的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,返回的是一个 Promise 对象。因此,可以把它放在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令后面。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const asyncIterable <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">createAsyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  const asyncIterator <span class="token operator" style="color:rgb(249,38,114);">=</span> asyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">[</span>Symbol<span class="token punctuation" style="color:rgb(248,248,242);">.</span>asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // { value: 'a', done: false }
</span>  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // { value: 'b', done: false }
</span>  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>await asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // { value: undefined, done: true }
</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>处理以后,就不必使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">then</code>方法了。整个流程已经很接近同步处理了。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">注意,异步遍历器的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法是可以连续调用的,不必等到上一步产生的 Promise 对象<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolve</code>以后再调用。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">这种情况下,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法会累积起来,自动按照每一步的顺序运行下去。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面是一个例子,把所有的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法放在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Promise.all</code>方法里面。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">const asyncGenObj <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">createAsyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
const <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span>value<span class="token punctuation" style="color:rgb(248,248,242);">:</span> v1<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>value<span class="token punctuation" style="color:rgb(248,248,242);">:</span> v2<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span> <span class="token operator" style="color:rgb(249,38,114);">=</span> await Promise<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">all<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">[</span>
  asyncGenObj<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> asyncGenObj<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>v1<span class="token punctuation" style="color:rgb(248,248,242);">,</span> v2<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // a b
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">另一种用法是一次性调用所有的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,然后<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>最后一步操作。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">runner<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const writer <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">openFile<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'someFile.txt'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  writer<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'hello'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  writer<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'world'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  await writer<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">return</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">runner<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <h3 class="for-await---of" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">for await...of</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">前面介绍过,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for...of</code>循环用于遍历同步的 Iterator 接口。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">新引入的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>循环,则是用于遍历异步的 Iterator 接口。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const x of <span class="token function">createAsyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>x<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token comment" style="color:rgb(117,113,94);">
// a
</span><span class="token comment" style="color:rgb(117,113,94);">// b
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">createAsyncIterable()</code>返回一个拥有异步遍历器接口的对象,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for...of</code>循环自动调用这个对象的异步遍历器的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,会得到一个 Promise 对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>用来处理这个 Promise 对象,一旦<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">resolve</code>,就把得到的值(<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">x</code>)传入<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for...of</code>的循环体。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>循环的一个用途,是部署了 asyncIterable 操作的异步接口,可以直接放入这个循环。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">let</span> body <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token string">''</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token function">await<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>const data of req<span class="token punctuation" style="color:rgb(248,248,242);">)</span> body <span class="token operator" style="color:rgb(249,38,114);">+</span><span class="token operator" style="color:rgb(249,38,114);">=</span> data<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  const parsed <span class="token operator" style="color:rgb(249,38,114);">=</span> JSON<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">parse<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>body<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'got'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> parsed<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">req</code>是一个 asyncIterable 对象,用来异步读取数据。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">可以看到,使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>循环以后,代码会非常简洁。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法返回的 Promise 对象被<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>就会报错,要用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">try...catch</code>捕捉。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const x of <span class="token function">createRejectingIterable<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>x<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">catch</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token class-name">e</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">error<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>e<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">注意,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>循环也可以用于同步遍历器。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token punctuation" style="color:rgb(248,248,242);">(</span>async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const x of <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>x<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);">
// a
</span><span class="token comment" style="color:rgb(117,113,94);">// b
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">Node v10 支持异步遍历器,Stream 就部署了这个接口。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面是读取文件的传统写法与异步遍历器写法的差异。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token comment" style="color:rgb(117,113,94);">// 传统写法
</span><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">main<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>inputFilePath<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const readStream <span class="token operator" style="color:rgb(249,38,114);">=</span> fs<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">createReadStream<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>
    inputFilePath<span class="token punctuation" style="color:rgb(248,248,242);">,</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">{</span> encoding<span class="token punctuation" style="color:rgb(248,248,242);">:</span> <span class="token string">'utf8'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> highWaterMark<span class="token punctuation" style="color:rgb(248,248,242);">:</span> <span class="token number" style="color:rgb(174,129,255);">1024</span> <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  readStream<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">on<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'data'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>chunk<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'>>> '</span><span class="token operator" style="color:rgb(249,38,114);">+</span>chunk<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  readStream<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">on<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'end'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'### DONE ###'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 异步遍历器写法
</span>async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">main<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>inputFilePath<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const readStream <span class="token operator" style="color:rgb(249,38,114);">=</span> fs<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">createReadStream<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>
    inputFilePath<span class="token punctuation" style="color:rgb(248,248,242);">,</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">{</span> encoding<span class="token punctuation" style="color:rgb(248,248,242);">:</span> <span class="token string">'utf8'</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span> highWaterMark<span class="token punctuation" style="color:rgb(248,248,242);">:</span> <span class="token number" style="color:rgb(174,129,255);">1024</span> <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

  <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const chunk of readStream<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'>>> '</span><span class="token operator" style="color:rgb(249,38,114);">+</span>chunk<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'### DONE ###'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <h3 class="异步-Generator-函数" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">异步 Generator 函数</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">就像 Generator 函数返回一个同步遍历器对象一样,异步 Generator 函数的作用,是返回一个异步遍历器对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">在语法上,异步 Generator 函数就是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">async</code>函数与 Generator 函数的结合。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">gen<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  yield <span class="token string">'hello'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
const genObj <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">gen<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
genObj<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>x <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>x<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);">
// { value: 'hello', done: false }
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">gen</code>是一个异步 Generator 函数,执行后返回一个异步 Iterator 对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">对该对象调用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,返回一个 Promise 对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步遍历器的设计目的之一,就是 Generator 函数处理同步操作和异步操作时,能够使用同一套接口。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token comment" style="color:rgb(117,113,94);">// 同步 Generator 函数
</span><span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">map<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterable<span class="token punctuation" style="color:rgb(248,248,242);">,</span> func<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const iter <span class="token operator" style="color:rgb(249,38,114);">=</span> iterable<span class="token punctuation" style="color:rgb(248,248,242);">[</span>Symbol<span class="token punctuation" style="color:rgb(248,248,242);">.</span>iterator<span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">while</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token boolean" style="color:rgb(174,129,255);">true</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const <span class="token punctuation" style="color:rgb(248,248,242);">{</span>value<span class="token punctuation" style="color:rgb(248,248,242);">,</span> done<span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token operator" style="color:rgb(249,38,114);">=</span> iter<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token keyword" style="color:rgb(102,217,239);">if</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>done<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token keyword" style="color:rgb(102,217,239);">break</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    yield <span class="token function">func<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>value<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token comment" style="color:rgb(117,113,94);">
// 异步 Generator 函数
</span>async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">map<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>iterable<span class="token punctuation" style="color:rgb(248,248,242);">,</span> func<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const iter <span class="token operator" style="color:rgb(249,38,114);">=</span> iterable<span class="token punctuation" style="color:rgb(248,248,242);">[</span>Symbol<span class="token punctuation" style="color:rgb(248,248,242);">.</span>asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">while</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token boolean" style="color:rgb(174,129,255);">true</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const <span class="token punctuation" style="color:rgb(248,248,242);">{</span>value<span class="token punctuation" style="color:rgb(248,248,242);">,</span> done<span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token operator" style="color:rgb(249,38,114);">=</span> await iter<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token keyword" style="color:rgb(102,217,239);">if</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>done<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token keyword" style="color:rgb(102,217,239);">break</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    yield <span class="token function">func<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>value<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">map</code>是一个 Generator 函数,第一个参数是可遍历对象<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">iterable</code>,第二个参数是一个回调函数<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">func</code>。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">map</code>的作用是将<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">iterable</code>每一步返回的值,使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">func</code>进行处理。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面有两个版本的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">map</code>,前一个处理同步遍历器,后一个处理异步遍历器,可以看到两个版本的写法基本上是一致的。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面是另一个异步 Generator 函数的例子。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">readLines<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>path<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">let</span> file <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">fileOpen<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>path<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>

  <span class="token keyword" style="color:rgb(102,217,239);">try</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    <span class="token keyword" style="color:rgb(102,217,239);">while</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token operator" style="color:rgb(249,38,114);">!</span>file<span class="token punctuation" style="color:rgb(248,248,242);">.</span>EOF<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
      yield await file<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">readLine<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token keyword" style="color:rgb(102,217,239);">finally</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    await file<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">close<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,异步操作前面使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>关键字标明,即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>后面的操作,应该返回 Promise 对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">凡是使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>关键字的地方,就是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法停下来的地方,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">它后面的表达式的值(即<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await file.readLine()</code>的值),会作为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next()</code>返回对象的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code>属性,这一点是与同步 Generator 函数一致的。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步 Generator 函数内部,能够同时使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>和<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>命令。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">可以这样理解,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令用于将外部操作产生的值输入函数内部,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>命令用于将函数内部的值输出。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码定义的异步 Generator 函数的用法如下。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token punctuation" style="color:rgb(248,248,242);">(</span>async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const line of <span class="token function">readLines<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>filePath<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>line<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步 Generator 函数可以与<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>循环结合起来使用。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">prefixLines<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>asyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const line of asyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    yield <span class="token string">'> '</span> <span class="token operator" style="color:rgb(249,38,114);">+</span> line<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步 Generator 函数的返回值是一个异步 Iterator,即每次调用它的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法,会返回一个 Promise 对象,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">也就是说,跟在<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>命令后面的,应该是一个 Promise 对象。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">fetchRandom<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const url <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token string">'https://www.random.org/decimal-fractions/'</span>
    <span class="token operator" style="color:rgb(249,38,114);">+</span> <span class="token string">'?num=1&dec=10&col=1&format=plain&rnd=new'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token function">fetch<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>url<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">asyncGenerator<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'Start'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  const result <span class="token operator" style="color:rgb(249,38,114);">=</span> await <span class="token function">fetchRandom<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // (A)
</span>  yield <span class="token string">'Result: '</span> <span class="token operator" style="color:rgb(249,38,114);">+</span> await result<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // (B)
</span>  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'Done'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

const ag <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">asyncGenerator<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
ag<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">{</span>value<span class="token punctuation" style="color:rgb(248,248,242);">,</span> done<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>value<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">ag</code>是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">asyncGenerator</code>函数返回的异步遍历器对象。调用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">ag.next()</code>以后,上面代码的执行顺序如下。</p> 
  <ol style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"> 
   <li style="text-indent:-5px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">ag.next()</code>立刻返回一个 Promise 对象。</li> 
   <li style="text-indent:-5px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">asyncGenerator</code>函数开始执行,打印出<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">Start</code>。</li> 
   <li style="text-indent:-5px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令返回一个 Promise 对象,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">asyncGenerator</code>函数停在这里。</li> 
   <li style="text-indent:-5px;">A 处变成 fulfilled 状态,产生的值放入<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">result</code>变量,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">asyncGenerator</code>函数继续往下执行。</li> 
   <li style="text-indent:-5px;">函数在 B 处的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>暂停执行,一旦<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code>命令取到值,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">ag.next()</code>返回的那个 Promise 对象变成 fulfilled 状态。</li> 
   <li style="text-indent:-5px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">ag.next()</code>后面的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">then</code>方法指定的回调函数开始执行。该回调函数的参数是一个对象<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">{value, done}</code><span style="font-size:15.36px;">,其中</span><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">value</code><span style="font-size:15.36px;">的值是</span><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield</code><span style="font-size:15.36px;">命令后面的那个表达式的值,</span><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code><span style="font-size:15.36px;">的值是</span><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">false</code><span style="font-size:15.36px;">。</span></li> 
  </ol> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">A 和 B 两行的作用类似于下面的代码。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Promise</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>resolve<span class="token punctuation" style="color:rgb(248,248,242);">,</span> reject<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token function">fetchRandom<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>result <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> result<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">text<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>result <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
     <span class="token function">resolve<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">{</span>
       value<span class="token punctuation" style="color:rgb(248,248,242);">:</span> <span class="token string">'Result: '</span> <span class="token operator" style="color:rgb(249,38,114);">+</span> result<span class="token punctuation" style="color:rgb(248,248,242);">,</span>
       done<span class="token punctuation" style="color:rgb(248,248,242);">:</span> <span class="token boolean" style="color:rgb(174,129,255);">false</span><span class="token punctuation" style="color:rgb(248,248,242);">,</span>
     <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果异步 Generator 函数抛出错误,会导致 Promise 对象的状态变为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">reject</code>,然后抛出的错误被<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">catch</code>方法捕获。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">asyncGenerator<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">throw</span> <span class="token keyword" style="color:rgb(102,217,239);">new</span> <span class="token class-name">Error</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token string">'Problem!'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">asyncGenerator<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">catch</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span>err <span class="token operator" style="color:rgb(249,38,114);">=</span><span class="token operator" style="color:rgb(249,38,114);">></span> console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>err<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // Error: Problem!
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">注意,普通的 async 函数返回的是一个 Promise 对象,而异步 Generator 函数返回的是一个异步 Iterator 对象。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">可以这样理解,async 函数和异步 Generator 函数,是封装异步操作的两种方法,都用来达到同一种目的<span style="font-size:15.36px;">。</span></p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><span style="font-size:15.36px;">区别在于,前者自带执行器,后者通过</span><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code><span style="font-size:15.36px;">执行,或者自己编写执行器。</span></p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><span style="font-size:15.36px;">下面就是一个异步 Generator 函数的执行器。</span></p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">takeAsync<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>asyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">,</span> count <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token number" style="color:rgb(174,129,255);">Infinity</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  const result <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token punctuation" style="color:rgb(248,248,242);">[</span><span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  const iterator <span class="token operator" style="color:rgb(249,38,114);">=</span> asyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">[</span>Symbol<span class="token punctuation" style="color:rgb(248,248,242);">.</span>asyncIterator<span class="token punctuation" style="color:rgb(248,248,242);">]</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">while</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>result<span class="token punctuation" style="color:rgb(248,248,242);">.</span>length <span class="token operator" style="color:rgb(249,38,114);"><</span> count<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    const <span class="token punctuation" style="color:rgb(248,248,242);">{</span>value<span class="token punctuation" style="color:rgb(248,248,242);">,</span> done<span class="token punctuation" style="color:rgb(248,248,242);">}</span> <span class="token operator" style="color:rgb(249,38,114);">=</span> await iterator<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    <span class="token keyword" style="color:rgb(102,217,239);">if</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>done<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token keyword" style="color:rgb(102,217,239);">break</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    result<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">push<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>value<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> result<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,异步 Generator 函数产生的异步遍历器,会通过<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">while</code>循环自动执行,</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">每当<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await iterator.next()</code>完成,就会进入下一轮循环。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">一旦<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">done</code>属性变为<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">true</code>,就会跳出循环,异步遍历器执行结束。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">下面是这个自动执行器的一个使用实例。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">gen<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    yield <span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    yield <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
    yield <span class="token string">'c'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>

  <span class="token keyword" style="color:rgb(102,217,239);">return</span> await <span class="token function">takeAsync<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token function">gen<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

<span class="token function">f<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">then<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>result<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>result<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // ['a', 'b', 'c']
</span><span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步 Generator 函数出现以后,JavaScript 就有了四种函数形式:</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">普通函数、async 函数、Generator 函数和异步 Generator 函数。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">请注意区分每种函数的不同之处。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">基本上,如果是一系列按照顺序执行的异步操作(比如读取文件,然后写入新内容,再存入硬盘),可以使用 async 函数;</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">如果是一系列产生相同数据结构的异步操作(比如一行一行读取文件),可以使用异步 Generator 函数。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">异步 Generator 函数也可以通过<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法的参数,接收外部传入的数据。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">const writer <span class="token operator" style="color:rgb(249,38,114);">=</span> <span class="token function">openFile<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'someFile.txt'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
writer<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'hello'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // 立即执行
</span>writer<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">next<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token string">'world'</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // 立即执行
</span>await writer<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token keyword" style="color:rgb(102,217,239);">return</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);"> // 等待写入结束
</span></code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">openFile</code>是一个异步 Generator 函数。<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法的参数,向该函数内部的操作传入数据。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">每次<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">next</code>方法都是同步执行的,最后的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>命令用于等待整个写入操作结束。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">最后,同步的数据结构,也可以使用异步 Generator 函数。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">createAsyncIterable<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>syncIterable<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const elem of syncIterable<span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    yield elem<span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,由于没有异步操作,所以也就没有使用<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">await</code>关键字。</p> 
  <h3 class="yield--语句" style="margin-top:50px;margin-bottom:0px;padding-top:20px;padding-bottom:0px;text-align:left;border-top:1px dotted rgb(119,119,119);color:rgb(51,51,51);font-family:Verdana, Arial;">yield* 语句</h3> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;"><code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield*</code>语句也可以跟一个异步遍历器。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);">async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">gen1<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  yield <span class="token string">'a'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  yield <span class="token string">'b'</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token keyword" style="color:rgb(102,217,239);">return</span> <span class="token number" style="color:rgb(174,129,255);">2</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>

async <span class="token keyword" style="color:rgb(102,217,239);">function</span><span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">gen2<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
 <span class="token comment" style="color:rgb(117,113,94);"> // result 最终会等于 2
</span>  const result <span class="token operator" style="color:rgb(249,38,114);">=</span> yield<span class="token operator" style="color:rgb(249,38,114);">*</span> <span class="token function">gen1<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span>
</code></code></pre> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">上面代码中,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">gen2</code>函数里面的<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">result</code>变量,最后的值是<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">2</code>。</p> 
  <p style="color:rgb(51,51,51);font-family:Verdana, Arial;font-size:15.36px;">与同步 Generator 函数一样,<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">for await...of</code>循环会展开<code style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;padding-left:3px;padding-right:3px;">yield*</code>。</p> 
  <pre><code class="language-javascript"><code class="language-javascript" style="font-family:Consolas, 'Courier New', Courier, FreeMono, monospace;color:rgb(166,226,46);word-spacing:normal;background:rgb(17,17,17);"><span class="token punctuation" style="color:rgb(248,248,242);">(</span>async <span class="token keyword" style="color:rgb(102,217,239);">function</span> <span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
  <span class="token keyword" style="color:rgb(102,217,239);">for</span> await <span class="token punctuation" style="color:rgb(248,248,242);">(</span>const x of <span class="token function">gen2<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span> <span class="token punctuation" style="color:rgb(248,248,242);">{</span>
    console<span class="token punctuation" style="color:rgb(248,248,242);">.</span><span class="token function">log<span class="token punctuation" style="color:rgb(248,248,242);">(</span></span>x<span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242);">}</span>
<span class="token punctuation" style="color:rgb(248,248,242);">}</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">(</span><span class="token punctuation" style="color:rgb(248,248,242);">)</span><span class="token punctuation" style="color:rgb(248,248,242);">;</span><span class="token comment" style="color:rgb(117,113,94);">
// a
</span><span class="token comment" style="color:rgb(117,113,94);">// b</span></code></code></pre> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><br></p> 
  <p><span style="color:rgb(255,0,0);font-family:Verdana, Arial, Helvetica, sans-serif;font-weight:700;background-color:rgb(255,255,255);">未完待续,下一章节,つづく</span><br></p> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1305317366296514560"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(JS/ES6)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1903915899207872512.htm"
                           title="使用hel-micro微服务实现在jsp项目中引入react组件" target="_blank">使用hel-micro微服务实现在jsp项目中引入react组件</a>
                        <span class="text-muted">小灰灰学编程</span>
<a class="tag" taget="_blank" href="/search/%E5%BE%AE%E6%9C%8D%E5%8A%A1/1.htm">微服务</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E6%9C%8D%E5%8A%A1/1.htm">微服务</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/jsp/1.htm">jsp</a><a class="tag" taget="_blank" href="/search/hel-micro/1.htm">hel-micro</a>
                        <div>以下是一个完整的示例,涵盖React子应用配置、JSP主应用集成以及样式隔离的实现细节。我们将通过CSSModules和ShadowDOM确保React样式与JSP样式互不干扰。一、React子应用配置1.项目结构react-module/├──src/│├──index.js#模块入口文件│├──App.js#React组件│└──App.module.css#组件样式(CSSModules)├</div>
                    </li>
                    <li><a href="/article/1903914890234490880.htm"
                           title="StarRocks中优雅处理JSON与列表字段的初步示例" target="_blank">StarRocks中优雅处理JSON与列表字段的初步示例</a>
                        <span class="text-muted">t.y.Tang</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a>
                        <div>StarRocks是一种兼容MySQL语法,自带对JSON,ARRAY等格式支持的数据库.文章目录一StarRocks是什么?与MySQL有何关系?二JSON格式的好处三JSON数组字段的应用和缺点四实例:StarRocks处理JSON数组的方法示例表结构场景1:筛选包含特定事件的用户场景2:提取数组中的嵌套字段场景3:展开数组为多行(UNNEST)场景4:复杂条件过滤(结合`$`索引)五,性能优</div>
                    </li>
                    <li><a href="/article/1903913757034213376.htm"
                           title="Vue——Vue-cli脚手架+前端路由" target="_blank">Vue——Vue-cli脚手架+前端路由</a>
                        <span class="text-muted">pdsu_zhao</span>
<a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/Vue%E5%AD%A6%E4%B9%A0%E4%B9%8B%E6%97%85/1.htm">Vue学习之旅</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/v-router/1.htm">v-router</a><a class="tag" taget="_blank" href="/search/v-resource/1.htm">v-resource</a><a class="tag" taget="_blank" href="/search/vue-cli/1.htm">vue-cli</a><a class="tag" taget="_blank" href="/search/ES6/1.htm">ES6</a>
                        <div>Vue-cli是Vue的脚手架工具可以进行目录结构、本地调试、代码部署、热加载、单元测试1、MVVM框架View——ViewModel——Model(视图)(通讯)(数据)“DOM”“观察者vue实例”“Javascript”注意:交互为双向的特点:(1)针对具有复杂交互逻辑的前端应用;(2)提供基础的架构抽象;(3)通过Ajax数据持久化,保证前端用户体验。2、什么是Vue.js它是一个轻量级M</div>
                    </li>
                    <li><a href="/article/1903900632503349248.htm"
                           title="RestTemplate和RPC区别" target="_blank">RestTemplate和RPC区别</a>
                        <span class="text-muted">酷爱码</span>
<a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a><a class="tag" taget="_blank" href="/search/rpc/1.htm">rpc</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/1.htm">网络协议</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a>
                        <div>RestTemplate是Spring框架中用于进行RESTful风格的HTTP请求的模板类,通常用于与外部服务进行通信。它基于HTTP协议,使用GET、POST、PUT、DELETE等HTTP方法来进行通信,传输的数据通常使用JSON或XML格式。它是一种基于资源的通信方式,通过URL来标识资源。RPC(RemoteProcedureCall)是一种远程过程调用的通信机制,用于不同进程或不同主机</div>
                    </li>
                    <li><a href="/article/1903898742252171264.htm"
                           title="深入浅出:序列化与反序列化的全面解析" target="_blank">深入浅出:序列化与反序列化的全面解析</a>
                        <span class="text-muted">进击的小白菜</span>
<a class="tag" taget="_blank" href="/search/%E4%B8%80%E4%BA%9B%E5%BC%80%E5%8F%91%E5%B8%B8%E8%AF%86/1.htm">一些开发常识</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E5%B8%B8%E8%AF%86/1.htm">开发常识</a>
                        <div>文章目录1.引言2.什么是序列化?2.1为什么需要序列化?3.什么是反序列化?3.1反序列化的重要性4.序列化与反序列化的实现4.1JSON(JavaScriptObjectNotation)4.2XML(eXtensibleMarkupLanguage)4.3ProtocolBuffers(Protobuf)4.4MessagePack5.安全性考虑6.性能优化7.结论附录:常见问题解答Q1:什</div>
                    </li>
                    <li><a href="/article/1903885371788292096.htm"
                           title="Cesium实践(1)—— Hello World" target="_blank">Cesium实践(1)—— Hello World</a>
                        <span class="text-muted">迦南giser</span>
<a class="tag" taget="_blank" href="/search/WebGIS/1.htm">WebGIS</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Cesium/1.htm">Cesium</a><a class="tag" taget="_blank" href="/search/webgis/1.htm">webgis</a><a class="tag" taget="_blank" href="/search/cesium/1.htm">cesium</a>
                        <div>文章目录前言Cesium是什么Cesium核心类ViewerSceneEntityDataSourceCollection创建第一个Cesium应用工程搭建Cesium版helloworld总结前言工作大半年来主要的技术栈是mapbox-gl和threejs,但是作为一名GIS专业毕业生,一直对Cesium充满兴趣。Cesium不仅保持了threejs的三维绘制能力,而且内置大量渲染地理数据的AP</div>
                    </li>
                    <li><a href="/article/1903883482262728704.htm"
                           title="Electron打包文件生成.exe文件打开即可使用" target="_blank">Electron打包文件生成.exe文件打开即可使用</a>
                        <span class="text-muted">糕冷小美n</span>
<a class="tag" taget="_blank" href="/search/electron/1.htm">electron</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>1、Electron打包,包括需要下载的内容和环境配置步骤注意:Electron是一个使用JavaScript、HTML和CSS构建跨平台桌面应用程序的框架首先需要电脑环境有Node.js和npm我之前的文章有关nvm下载node的说明也可以去官网下载检查是否有node和npm环境命令node-vnpm-v输出版本号,说明安装成功2、创建Electron项目2.1创建项目目录打开命令行工具,创建一</div>
                    </li>
                    <li><a href="/article/1903876660910944256.htm"
                           title="Three.js世界中的三要素:场景、相机、渲染器" target="_blank">Three.js世界中的三要素:场景、相机、渲染器</a>
                        <span class="text-muted">Front_Yue</span>
<a class="tag" taget="_blank" href="/search/3D%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/1.htm">3D技术实践指南</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/three.js/1.htm">three.js</a><a class="tag" taget="_blank" href="/search/3d/1.htm">3d</a>
                        <div>一、Three.js简介Three.js是一个基于WebGL的JavaScript库,它允许开发者在网页上创建和显示复杂的3D图形和动画,而无需用户安装任何额外的插件或软件。Three.js在Web开发中的地位非常重要,它通过提供简单直观的API,极大地降低了3D图形开发的门槛,使得开发者可以更专注于实现创意。Three.js广泛应用于游戏开发、虚拟现实、数据可视化、艺术创作等多个领域。二、场景:</div>
                    </li>
                    <li><a href="/article/1903876407671451648.htm"
                           title="【终极解决方案】基于pm2来运行ts文件【和运行js差距很大哦】TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension “.ts“" target="_blank">【终极解决方案】基于pm2来运行ts文件【和运行js差距很大哦】TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension “.ts“</a>
                        <span class="text-muted">weixin_43343144</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>GPT最开始推荐的方案是:pm2startxx.ts--interpreterts-node-esm但是使用你用的是--interpreterts-node-esm但仍然报TypeError[ERR_UNKNOWN_FILE_EXTENSION]:Unknownfileextension".ts"最终的解决方案:pm2startxx.ts--namexx--interpreternode--nod</div>
                    </li>
                    <li><a href="/article/1903873762076454912.htm"
                           title="PHP框架为基础的购物平台设计思路分步骤说明" target="_blank">PHP框架为基础的购物平台设计思路分步骤说明</a>
                        <span class="text-muted">星糖曙光</span>
<a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF%E8%AF%AD%E8%A8%80%EF%BC%88node/1.htm">后端语言(node</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue%E7%AD%89%E7%AD%89%EF%BC%89/1.htm">vue等等)</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/php/1.htm">php</a>
                        <div>以下是以PHP框架为基础的购物平台设计思路分步骤说明:一、技术选型阶段技术栈={后端框架:Laravel/Yii2(提供ORM、路由、中间件支持)前端框架:Vue.js/React(可选SPA方案)数据库:MySQL8.0+(事务型数据存储)缓存:Redis(会话/商品缓存)队列:RabbitMQ(异步处理订单)\text{技术栈}=\begin{cases}后端框架:Laravel/Yii2(提</div>
                    </li>
                    <li><a href="/article/1903866571588169728.htm"
                           title="C++在线OJ负载均衡项目" target="_blank">C++在线OJ负载均衡项目</a>
                        <span class="text-muted">平凡的小y</span>
<a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>1.演示项目项目源码链接:2.项目所用技术和开发环境所用技术C++STL标准库Boost准标准库(字符串切割)cpp-httplib第三方开源网络库ctemplate第三方开源前端网页渲染库jsoncpp第三方开源序列化、反序列化库负载均衡设计MySQLCconnectAce前端在线编辑器html/css/js/jquery/ajax开发环境Ubuntu云服务器vscodeMysqlWorkben</div>
                    </li>
                    <li><a href="/article/1903861275209822208.htm"
                           title="npm install 报错 gyp info it worked if it ends with ok npm ERR gyp verb cli [" target="_blank">npm install 报错 gyp info it worked if it ends with ok npm ERR gyp verb cli [</a>
                        <span class="text-muted">m0_61083409</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>今天新启动一个项目,在npminstall安装依赖项时出现报错。ERR!code1npmERR!pathC:UsersAdministratorDesktope31mall-admin-webode_modulesode-sassnpmERR!commandfailednpmERR!commandC:Windowssystem32cmd.exe/d/s/cnodescripts/build.jsn</div>
                    </li>
                    <li><a href="/article/1903861274085748736.htm"
                           title="npm错误 gyp错误 vs版本不对 msvs_version不兼容" target="_blank">npm错误 gyp错误 vs版本不对 msvs_version不兼容</a>
                        <span class="text-muted">澎湖Java架构师</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>npm错误gyp错误vs版本不对msvs_version不兼容windowsSDK报错执行更新GYP语句第一种方案第二种方案执行更新GYP语句npminstall-gnode-gyp最新的GYP好像已经不支持Python2.7版本,npm会提示你更新都3.*.*版本安装Node.js的时候一定要勾选以下这个,会自动检测安装缺少的环境第一种方案管理员运行CMD(PowerShell也行)执行更新工具</div>
                    </li>
                    <li><a href="/article/1903860767069892608.htm"
                           title="深入了解 ArangoDB 的图数据库应用与 Python 实践" target="_blank">深入了解 ArangoDB 的图数据库应用与 Python 实践</a>
                        <span class="text-muted">eahba</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>在当前数据驱动的时代,对连接数据的高效处理和分析需求日益增长。ArangoDB作为一个可扩展的图数据库系统,能够加速从连接数据中获取价值。本文将介绍如何使用Python连接和操作ArangoDB,并展示如何结合图问答链来获取数据洞察。技术背景介绍ArangoDB是一个多模型数据库,支持文档、图和键值类型的数据存储。其强大的图形存储和查询能力使其成为处理复杂数据关系的理想选择。通过JSON支持和单一</div>
                    </li>
                    <li><a href="/article/1903859506308247552.htm"
                           title="基于JAVA中的spring框架和jsp实现自然灾害论坛平台项目【附项目源码+论文说明】" target="_blank">基于JAVA中的spring框架和jsp实现自然灾害论坛平台项目【附项目源码+论文说明】</a>
                        <span class="text-muted">大雄是个程序员</span>
<a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5/1.htm">项目实践</a><a class="tag" taget="_blank" href="/search/%E8%87%AA%E7%84%B6%E7%81%BE%E5%AE%B3%E8%AE%BA%E5%9D%9B%E5%B9%B3%E5%8F%B0/1.htm">自然灾害论坛平台</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E6%BA%90%E7%A0%81/1.htm">项目源码</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1/1.htm">毕业设计</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1/1.htm">网页设计</a>
                        <div>摘要在上个世纪末期,也就是20世纪末,随着计算机技术的发展与进步和数据库方面的知识在互联网的大力运用,互联网技术以及网站技术在网上的大力推广,网上论坛(自然灾害论坛)也逐渐在网兴起,它的出现帮助了网上各种特定的群体进行一个在线的知识传递与信息的交流。本计算机自然灾害论坛设计,采用了JSP(JAVA)技术和MYSQL数据库开发,尝试实现了自然灾害论坛的基本功能以及帮助我们掌握了论坛技术的核心特点。该</div>
                    </li>
                    <li><a href="/article/1903858120061415424.htm"
                           title="npm error gyp info" target="_blank">npm error gyp info</a>
                        <span class="text-muted">计算机辅助工程</span>
<a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>在使用npm安装Node.js包时,可能会遇到各种错误,其中gyp错误是比较常见的一种。gyp是Node.js的一个工具,用于编译C++代码。这些错误通常发生在需要编译原生模块的npm包时。下面是一些常见的原因和解决方法:常见原因及解决方法Python未安装或版本不兼容:Node.js使用Python来运行gyp。确保你的系统上安装了Python,并且版本与node-gyp兼容。通常推荐使用Pyt</div>
                    </li>
                    <li><a href="/article/1903855472880971776.htm"
                           title="Font Awesome 的使用" target="_blank">Font Awesome 的使用</a>
                        <span class="text-muted">FFF-X</span>

                        <div>第一种直接使用命令npminstallfont-awesome--save进行安装,安装成功后里面包含样式和字体,然后直接引入样式就可以了入口js中引入import'font-awesome/css/font-awesome.min.css'然后就可以使用了,例如下面这样第二种cdn要使用FontAwesome图标,请在HTML页面的部分中添加以下行:1、国内推荐CDN:2、海外推荐CDN推荐第二</div>
                    </li>
                    <li><a href="/article/1903851687404171264.htm"
                           title="JS基础-事件模型(事件&事件流&自定义事件&事件冒泡/代理)" target="_blank">JS基础-事件模型(事件&事件流&自定义事件&事件冒泡/代理)</a>
                        <span class="text-muted">LYFlied</span>
<a class="tag" taget="_blank" href="/search/html%26amp%3B%E6%B5%8F%E8%A7%88%E5%99%A8/1.htm">html&浏览器</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E4%BA%8B%E4%BB%B6%E6%A8%A1%E5%9E%8B/1.htm">事件模型</a><a class="tag" taget="_blank" href="/search/%E4%BA%8B%E4%BB%B6%E6%B5%81/1.htm">事件流</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a>
                        <div>文章目录一、事件与事件流二、事件模型1.DOM0级模型2.IE事件模型3.DOM2级模型4.DOM3级事件处理方式三、事件对象四、事件绑定与解除1.事件绑定1.1对象.on事件名字=事件处理函数1.2.对象.addEventListener("没有on的事件名字",事件处理函数,false)3.对象.attachEvent("有on的事件名字",事件处理函数);2.解除绑定五、EventWrapp</div>
                    </li>
                    <li><a href="/article/1903850929363415040.htm"
                           title="JavaScript基础-DOM的一些基本常用语法" target="_blank">JavaScript基础-DOM的一些基本常用语法</a>
                        <span class="text-muted">Southern Wind</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>总结了一下JS一直到DOM中所用的单词的用法输入方式:window.prompt('请输入数据');输出方式:1、window.alert('HelloJavaScript');2、console.log输出到控制台3、输出数据到页面document.write('hello')JavaScript数据类型1、基本类型string:字符型number:数值型boolean:布尔型2、特殊类型und</div>
                    </li>
                    <li><a href="/article/1903850677071835136.htm"
                           title="通过浏览器扩展获取本机 MAC 地址" target="_blank">通过浏览器扩展获取本机 MAC 地址</a>
                        <span class="text-muted">云水木石</span>
<a class="tag" taget="_blank" href="/search/macos/1.htm">macos</a>
                        <div>在Web技术主导的B/S架构项目中,获取终端设备硬件信息(如MAC地址)的需求经常会碰到。尽管Electron/CEF等混合应用框架可通过系统级API轻松实现,但纯浏览器环境下的硬件信息获取则不那么容易。因为现代浏览器基于沙箱机制和隐私保护策略,严格禁止网页直接访问底层硬件资源。但用户的需求不能不考虑,特别是在做商业项目时,这时就不得不给出方案,总结下来有如下三种方案:扩展JSAPI:比如以前在做</div>
                    </li>
                    <li><a href="/article/1903847274174279680.htm"
                           title="穴位按摩培训系统Django-SpringBoot-php-Node.js-flask" target="_blank">穴位按摩培训系统Django-SpringBoot-php-Node.js-flask</a>
                        <span class="text-muted">QQ188083800</span>
<a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/php/1.htm">php</a>
                        <div>目录具体实现截图技术栈介绍系统设计研究方法:设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示具体实现截图技术栈介绍本课题的研究方法和研究步骤基本合理,难度适中,本选题是学生所学专业知识的延续,符合学生专业发展方向,对于提高学生的基本知识和技能以及钻研能力有益。该学生能够在预定时间内完成该课题的设计。研究的选题立意明确,结构合理,研究内容充实,研究方法准确有</div>
                    </li>
                    <li><a href="/article/1903846137262043136.htm"
                           title="vLLM - 查看模型是否支持" target="_blank">vLLM - 查看模型是否支持</a>
                        <span class="text-muted">云客Coder</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>支持的模型:https://docs.vllm.ai/en/latest/models/supported_models.html要确定是否支持给定模型,您可以检查HF存储库中的config.json文件。如果"architectures"字段包含下面列出的模型架构,那么理论上应该支持它。查看模型架构查看模型的config.json中的architecturescat~/.cache/huggin</div>
                    </li>
                    <li><a href="/article/1903835673773797376.htm"
                           title="fastjosn注册自定义序列化器" target="_blank">fastjosn注册自定义序列化器</a>
                        <span class="text-muted">林发和</span>
<a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                        <div>自定义序列化器:  importcom.alibaba.fastjson.serializer.JSONSerializer;  importcom.alibaba.fastjson.serializer.ObjectSerializer;  importorg.springframework.boot.actuate.health.Status;  importjava.io.IOExcepti</div>
                    </li>
                    <li><a href="/article/1903828236677214208.htm"
                           title="form 表单内容序列化成一个字符串" target="_blank">form 表单内容序列化成一个字符串</a>
                        <span class="text-muted">sayyy</span>
<a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a>
                        <div>html关键字1:关键字2:关键字3:form表单数据转json对象$('#form1').serialize()ajax调用时提交表单数据$.ajax({url:"http://localhost:8080/xxx",type:"POST",data:$('#form1').serialize(),success:function(data){$('#serverResponse').html(</div>
                    </li>
                    <li><a href="/article/1903823066094432256.htm"
                           title="Android Token的原理和本地安全存储" target="_blank">Android Token的原理和本地安全存储</a>
                        <span class="text-muted">Ya-Jun</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a>
                        <div>AndroidToken的原理和本地安全存储前言在移动应用开发中,Token是实现用户身份验证和授权的重要机制。本文将深入介绍Token的原理,以及在Android平台上如何安全地存储Token,帮助开发者构建可靠的身份验证系统。基础知识1.Token概述1.1Token的作用身份验证授权访问无状态设计1.2Token类型AccessTokenRefreshTokenJWT(JSONWebToke</div>
                    </li>
                    <li><a href="/article/1903809437764743168.htm"
                           title="前端性能优化-知识点" target="_blank">前端性能优化-知识点</a>
                        <span class="text-muted">甲亿</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/1.htm">性能优化</a>
                        <div>Web性能优化意义1.减少整体加载时间:减小文件体积、减少HTTP请求、使用预加载。2.使网站尽快可用:仅加载首屏内容,其他内容根据需要进行懒加载。3.平滑和交互性:使用CSS替代JS动画、减少UI重绘。4.加载表现形式:使用加载动画、进度条、骨架屏等过渡信息,让用户感觉到页面加载更快。5.性能监测:性能指标、性能测试、性能监控持续优化等Web性能指标RAIL性能模型Response(响应):快速</div>
                    </li>
                    <li><a href="/article/1903802880863825920.htm"
                           title="网络空间安全专业培养方案及学习建议" target="_blank">网络空间安全专业培养方案及学习建议</a>
                        <span class="text-muted">菜根Sec</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/1.htm">网络安全</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E7%A9%BA%E9%97%B4%E5%AE%89%E5%85%A8/1.htm">网络空间安全</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/1.htm">信息安全</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E5%AD%A6%E4%B8%93%E4%B8%9A/1.htm">大学专业</a>
                        <div>一、网络空间安全专业培养方案(示例)本文以武汉大学网络空间安全专业培养方案为例,列举本科期间学习的课程。详情参见:https://cse.whu.edu.cn/rcpy/lxspy/zyjs/wlkjaqzypyfa.htm1、培养目标网络空间安全学科是综台计算机、通信、电子、数学、物理、生物、管理、法律和教育等学科,并发展演绎而形成的交叉学科。培养的本科生要求掌握网络空间安全学科的基本理论、基本</div>
                    </li>
                    <li><a href="/article/1903783590831910912.htm"
                           title="nvm管理多版本node,nvm 配置国内镜像,npm配置国内镜像" target="_blank">nvm管理多版本node,nvm 配置国内镜像,npm配置国内镜像</a>
                        <span class="text-muted">奇纳尼</span>
<a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>目录前言nvm是什么?安装nvm配置nvm国内镜像nvm常用命令npm配置国内镜像:淘宝镜像nrm源管理命令:可以不用实际项目中会遇到的问题前言公司多个项目需要配置不同版本的node,按照传统方式一直切换下载安装不同版本的node太麻烦了,发现nvm可以管理多版本nodenvm是什么?nvm(node.jsversionmanagement),是一个nodejs的版本管理工具。nvm和n都是nod</div>
                    </li>
                    <li><a href="/article/1903783212719599616.htm"
                           title="autojs之乐旅商城自动报名自动约" target="_blank">autojs之乐旅商城自动报名自动约</a>
                        <span class="text-muted">恶猫</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/autojs/1.htm">autojs</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%8D%93%E8%84%9A%E6%9C%AC/1.htm">安卓脚本</a>
                        <div>之前用的。现在能不能用不知道了啊。自己测试吧。//一键亮屏device.wakeUp();device.wakeUpIfNeeded();sleep(1000);//滑开swipe(device.width/2,device.height*0.8,device.width/2,device.height*0.1,2000);sleep(2000);//一键开微信launchApp("微信");sl</div>
                    </li>
                    <li><a href="/article/1903781573514293248.htm"
                           title="pyspark学习rdd处理数据方法——学习记录" target="_blank">pyspark学习rdd处理数据方法——学习记录</a>
                        <span class="text-muted">亭午</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a>
                        <div>python黑马程序员"""文件,按JSON字符串存储1.城市按销售额排名2.全部城市有哪些商品类别在售卖3.上海市有哪些商品类别在售卖"""frompysparkimportSparkConf,SparkContextimportosimportjsonos.environ['PYSPARK_PYTHON']=r"D:\anaconda\envs\py10\python.exe"#创建Spark</div>
                    </li>
                                <li><a href="/article/56.htm"
                                       title="多线程编程之存钱与取钱" target="_blank">多线程编程之存钱与取钱</a>
                                    <span class="text-muted">周凡杨</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/thread/1.htm">thread</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/%E5%AD%98%E9%92%B1/1.htm">存钱</a><a class="tag" taget="_blank" href="/search/%E5%8F%96%E9%92%B1/1.htm">取钱</a>
                                    <div>  
生活费问题是这样的:学生每月都需要生活费,家长一次预存一段时间的生活费,家长和学生使用统一的一个帐号,在学生每次取帐号中一部分钱,直到帐号中没钱时 通知家长存钱,而家长看到帐户还有钱则不存钱,直到帐户没钱时才存钱。   
问题分析:首先问题中有三个实体,学生、家长、银行账户,所以设计程序时就要设计三个类。其中银行账户只有一个,学生和家长操作的是同一个银行账户,学生的行为是</div>
                                </li>
                                <li><a href="/article/183.htm"
                                       title="java中数组与List相互转换的方法" target="_blank">java中数组与List相互转换的方法</a>
                                    <span class="text-muted">征客丶</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jsonp/1.htm">jsonp</a>
                                    <div>1.List转换成为数组。(这里的List是实体是ArrayList) 
  调用ArrayList的toArray方法。 
  toArray 
  public T[] toArray(T[] a)返回一个按照正确的顺序包含此列表中所有元素的数组;返回数组的运行时类型就是指定数组的运行时类型。如果列表能放入指定的数组,则返回放入此列表元素的数组。否则,将根据指定数组的运行时类型和此列表的大小分</div>
                                </li>
                                <li><a href="/article/310.htm"
                                       title="Shell 流程控制" target="_blank">Shell 流程控制</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6/1.htm">流程控制</a><a class="tag" taget="_blank" href="/search/if+else/1.htm">if else</a><a class="tag" taget="_blank" href="/search/while/1.htm">while</a><a class="tag" taget="_blank" href="/search/case/1.htm">case</a><a class="tag" taget="_blank" href="/search/shell/1.htm">shell</a>
                                    <div>Shell 流程控制 
和Java、PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法): 
<?php
if(isset($_GET["q"])){
    search(q);}else{// 不做任何事情} 
在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else,就像这样  if else if 
if 语句语</div>
                                </li>
                                <li><a href="/article/437.htm"
                                       title="Linux服务器新手操作之二" target="_blank">Linux服务器新手操作之二</a>
                                    <span class="text-muted">周凡杨</span>
<a class="tag" taget="_blank" href="/search/Linux+%E7%AE%80%E5%8D%95+%E6%93%8D%E4%BD%9C/1.htm">Linux 简单 操作</a>
                                    <div>1.利用关键字搜寻Man Pages    man -k keyword  其中-k 是选项,keyword是要搜寻的关键字 如果现在想使用whoami命令,但是只记住了前3个字符who,就可以使用 man -k who来搜寻关键字who的man命令       [haself@HA5-DZ26 ~]$ man -k </div>
                                </li>
                                <li><a href="/article/564.htm"
                                       title="socket聊天室之服务器搭建" target="_blank">socket聊天室之服务器搭建</a>
                                    <span class="text-muted">朱辉辉33</span>
<a class="tag" taget="_blank" href="/search/socket/1.htm">socket</a>
                                    <div>因为我们做的是聊天室,所以会有多个客户端,每个客户端我们用一个线程去实现,通过搭建一个服务器来实现从每个客户端来读取信息和发送信息。 
   我们先写客户端的线程。 
public class ChatSocket extends Thread{ 
 Socket socket; 
 
 public ChatSocket(Socket socket){ 
 this.sock</div>
                                </li>
                                <li><a href="/article/691.htm"
                                       title="利用finereport建设保险公司决策分析系统的思路和方法" target="_blank">利用finereport建设保险公司决策分析系统的思路和方法</a>
                                    <span class="text-muted">老A不折腾</span>
<a class="tag" taget="_blank" href="/search/finereport/1.htm">finereport</a><a class="tag" taget="_blank" href="/search/%E9%87%91%E8%9E%8D%E4%BF%9D%E9%99%A9/1.htm">金融保险</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E6%9E%90%E7%B3%BB%E7%BB%9F/1.htm">分析系统</a><a class="tag" taget="_blank" href="/search/%E6%8A%A5%E8%A1%A8%E7%B3%BB%E7%BB%9F/1.htm">报表系统</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/1.htm">项目开发</a>
                                    <div>决策分析系统呈现的是数据页面,也就是俗称的报表,报表与报表间、数据与数据间都按照一定的逻辑设定,是业务人员查看、分析数据的平台,更是辅助领导们运营决策的平台。底层数据决定上层分析,所以建设决策分析系统一般包括数据层处理(数据仓库建设)。 
  
项目背景介绍 
通常,保险公司信息化程度很高,基本上都有业务处理系统(像集团业务处理系统、老业务处理系统、个人代理人系统等)、数据服务系统(通过</div>
                                </li>
                                <li><a href="/article/818.htm"
                                       title="始终要页面在ifream的最顶层" target="_blank">始终要页面在ifream的最顶层</a>
                                    <span class="text-muted">林鹤霄</span>

                                    <div>index.jsp中有ifream,但是session消失后要让login.jsp始终显示到ifream的最顶层。。。始终没搞定,后来反复琢磨之后,得到了解决办法,在这儿给大家分享下。。 
index.jsp--->主要是加了颜色的那一句 
<html> 
<iframe name="top" ></iframe> 
<ifram</div>
                                </li>
                                <li><a href="/article/945.htm"
                                       title="MySQL binlog恢复数据" target="_blank">MySQL binlog恢复数据</a>
                                    <span class="text-muted">aigo</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a>
                                    <div>1,先确保my.ini已经配置了binlog: 
  
# binlog
log_bin = D:/mysql-5.6.21-winx64/log/binlog/mysql-bin.log
log_bin_index = D:/mysql-5.6.21-winx64/log/binlog/mysql-bin.index
log_error = D:/mysql-5.6.21-win</div>
                                </li>
                                <li><a href="/article/1072.htm"
                                       title="OCX打成CBA包并实现自动安装与自动升级" target="_blank">OCX打成CBA包并实现自动安装与自动升级</a>
                                    <span class="text-muted">alxw4616</span>
<a class="tag" taget="_blank" href="/search/ocx/1.htm">ocx</a><a class="tag" taget="_blank" href="/search/cab/1.htm">cab</a>
                                    <div>近来手上有个项目,需要使用ocx控件 
(ocx是什么? 
http://baike.baidu.com/view/393671.htm) 
在生产过程中我遇到了如下问题. 
1. 如何让 ocx 自动安装? 
    a) 如何签名? 
    b) 如何打包? 
    c) 如何安装到指定目录? 
2.</div>
                                </li>
                                <li><a href="/article/1199.htm"
                                       title="Hashmap队列和PriorityQueue队列的应用" target="_blank">Hashmap队列和PriorityQueue队列的应用</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/Hashmap%E9%98%9F%E5%88%97/1.htm">Hashmap队列</a><a class="tag" taget="_blank" href="/search/PriorityQueue%E9%98%9F%E5%88%97/1.htm">PriorityQueue队列</a>
                                    <div>  
HashMap队列已经是学过了的,但是最近在用的时候不是很熟悉,刚刚重新看以一次, 
  HashMap是K,v键 ,值   
  
put()添加元素 
  
  
 //下面试HashMap去掉重复的 
package com.hashMapandPriorityQueue;

import java.util.H</div>
                                </li>
                                <li><a href="/article/1326.htm"
                                       title="JDK1.5 returnvalue实例" target="_blank">JDK1.5 returnvalue实例</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/thread/1.htm">thread</a><a class="tag" taget="_blank" href="/search/java%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">java多线程</a><a class="tag" taget="_blank" href="/search/returnvalue/1.htm">returnvalue</a>
                                    <div>Callable接口: 
返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。 
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。 
        
ExecutorService接口方</div>
                                </li>
                                <li><a href="/article/1453.htm"
                                       title="angularjs指令中动态编译的方法(适用于有异步请求的情况) 内嵌指令无效" target="_blank">angularjs指令中动态编译的方法(适用于有异步请求的情况) 内嵌指令无效</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a>
                                    <div>        在directive的link中有一个$http请求,当请求完成后根据返回的值动态做element.append('......');这个操作,能显示没问题,可问题是我动态组的HTML里面有ng-click,发现显示出来的内容根本不执行ng-click绑定的方法! 
    </div>
                                </li>
                                <li><a href="/article/1580.htm"
                                       title="【Java范型二】Java范型详解之extend限定范型参数的类型" target="_blank">【Java范型二】Java范型详解之extend限定范型参数的类型</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/extend/1.htm">extend</a>
                                    <div>在第一篇中,定义范型类时,使用如下的方式: 
  
public class Generics<M, S, N> {
   //M,S,N是范型参数
} 
 这种方式定义的范型类有两个基本的问题: 
  
1. 范型参数定义的实例字段,如private M m = null;由于M的类型在运行时才能确定,那么我们在类的方法中,无法使用m,这跟定义pri</div>
                                </li>
                                <li><a href="/article/1707.htm"
                                       title="【HBase十三】HBase知识点总结" target="_blank">【HBase十三】HBase知识点总结</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/hbase/1.htm">hbase</a>
                                    <div>1. 数据从MemStore flush到磁盘的触发条件有哪些? 
   a.显式调用flush,比如flush 'mytable' 
   b.MemStore中的数据容量超过flush的指定容量,hbase.hregion.memstore.flush.size,默认值是64M 2. Region的构成是怎么样? 
1个Region由若干个Store组成</div>
                                </li>
                                <li><a href="/article/1834.htm"
                                       title="服务器被DDOS攻击防御的SHELL脚本" target="_blank">服务器被DDOS攻击防御的SHELL脚本</a>
                                    <span class="text-muted">ronin47</span>

                                    <div>mkdir /root/bin
vi /root/bin/dropip.sh
#!/bin/bash/bin/netstat -na|grep ESTABLISHED|awk ‘{print $5}’|awk -F:‘{print $1}’|sort|uniq -c|sort -rn|head -10|grep -v -E ’192.168|127.0′|awk ‘{if($2!=null&a</div>
                                </li>
                                <li><a href="/article/1961.htm"
                                       title="java程序员生存手册-craps 游戏-一个简单的游戏" target="_blank">java程序员生存手册-craps 游戏-一个简单的游戏</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>
import java.util.Random;


public class CrapsGame {

	/**
	 *
	 *一个简单的赌*博游戏,游戏规则如下:
	 *玩家掷两个骰子,点数为1到6,如果第一次点数和为7或11,则玩家胜,
	 *如果点数和为2、3或12,则玩家输,
	 *如果和为其它点数,则记录第一次的点数和,然后继续掷骰,直至点数和等于第一次掷出的点</div>
                                </li>
                                <li><a href="/article/2088.htm"
                                       title="TOMCAT启动提示NB: JAVA_HOME should point to a JDK not a JRE解决" target="_blank">TOMCAT启动提示NB: JAVA_HOME should point to a JDK not a JRE解决</a>
                                    <span class="text-muted">开窍的石头</span>
<a class="tag" taget="_blank" href="/search/JAVA_HOME/1.htm">JAVA_HOME</a>
                                    <div>当tomcat是解压的时候,用eclipse启动正常,点击startup.bat的时候启动报错; 
报错如下: 
  The JAVA_HOME environment variable is not defined correctly 
This environment variable is needed to run this program 
NB: JAVA_HOME shou</div>
                                </li>
                                <li><a href="/article/2215.htm"
                                       title="[操作系统内核]操作系统与互联网" target="_blank">[操作系统内核]操作系统与互联网</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/1.htm">操作系统</a>
                                    <div> 
 
     我首先申明:我这里所说的问题并不是针对哪个厂商的,仅仅是描述我对操作系统技术的一些看法 
 
 
      操作系统是一种与硬件层关系非常密切的系统软件,按理说,这种系统软件应该是由设计CPU和硬件板卡的厂商开发的,和软件公司没有直接的关系,也就是说,操作系统应该由做硬件的厂商来设计和开发</div>
                                </li>
                                <li><a href="/article/2342.htm"
                                       title="富文本框ckeditor_4.4.7 文本框的简单使用 支持IE11" target="_blank">富文本框ckeditor_4.4.7 文本框的简单使用 支持IE11</a>
                                    <span class="text-muted">cuityang</span>
<a class="tag" taget="_blank" href="/search/%E5%AF%8C%E6%96%87%E6%9C%AC%E6%A1%86/1.htm">富文本框</a>
                                    <div><html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<title>知识库内容编辑</tit</div>
                                </li>
                                <li><a href="/article/2469.htm"
                                       title="Property null not found" target="_blank">Property null not found</a>
                                    <span class="text-muted">darrenzhu</span>
<a class="tag" taget="_blank" href="/search/datagrid/1.htm">datagrid</a><a class="tag" taget="_blank" href="/search/Flex/1.htm">Flex</a><a class="tag" taget="_blank" href="/search/Advanced/1.htm">Advanced</a><a class="tag" taget="_blank" href="/search/propery+null/1.htm">propery null</a>
                                    <div>When you got error message like "Property null not found ***", try to fix it by the following way: 
 
1)if you are using AdvancedDatagrid, make sure you only update the data in the data prov</div>
                                </li>
                                <li><a href="/article/2596.htm"
                                       title="MySQl数据库字符串替换函数使用" target="_blank">MySQl数据库字符串替换函数使用</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E5%87%BD%E6%95%B0/1.htm">函数</a><a class="tag" taget="_blank" href="/search/%E6%9B%BF%E6%8D%A2/1.htm">替换</a>
                                    <div>需求:需要将数据表中一个字段的值里面的所有的  .   替换成  _   
原来的数据是  site.title  site.keywords  .... 
替换后要为     site_title  site_keywords 
  
使用的SQL语句如下: 
  
updat</div>
                                </li>
                                <li><a href="/article/2723.htm"
                                       title="mac上终端起动MySQL的方法" target="_blank">mac上终端起动MySQL的方法</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/mac/1.htm">mac</a>
                                    <div>首先去官网下载: http://www.mysql.com/downloads/ 
我下载了5.6.11的dmg然后安装,安装完成之后..如果要用终端去玩SQL.那么一开始要输入很长的:/usr/local/mysql/bin/mysql 
这不方便啊,好想像windows下的cmd里面一样输入mysql -uroot -p1这样...上网查了下..可以实现滴. 
打开终端,输入: 
1</div>
                                </li>
                                <li><a href="/article/2850.htm"
                                       title="Gson使用一(Gson)" target="_blank">Gson使用一(Gson)</a>
                                    <span class="text-muted">eksliang</span>
<a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/gson/1.htm">gson</a>
                                    <div>转载请出自出处:http://eksliang.iteye.com/blog/2175401 一.概述 
从结构上看Json,所有的数据(data)最终都可以分解成三种类型: 
 
 第一种类型是标量(scalar),也就是一个单独的字符串(string)或数字(numbers),比如"ickes"这个字符串。 
 第二种类型是序列(sequence),又叫做数组(array)</div>
                                </li>
                                <li><a href="/article/2977.htm"
                                       title="android点滴4" target="_blank">android点滴4</a>
                                    <span class="text-muted">gundumw100</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a>
                                    <div>Android 47个小知识 
 
http://www.open-open.com/lib/view/open1422676091314.html 
 
 Android实用代码七段(一) 
 
http://www.cnblogs.com/over140/archive/2012/09/26/2611999.html 
 
http://www.cnblogs.com/over140/arch</div>
                                </li>
                                <li><a href="/article/3104.htm"
                                       title="JavaWeb之JSP基本语法" target="_blank">JavaWeb之JSP基本语法</a>
                                    <span class="text-muted">ihuning</span>
<a class="tag" taget="_blank" href="/search/javaweb/1.htm">javaweb</a>
                                    <div>  
目录 
  
JSP模版元素  
JSP表达式  
JSP脚本片断  
EL表达式  
JSP注释  
特殊字符序列的转义处理  
如何查找JSP页面中的错误 
  
JSP模版元素  
  
JSP页面中的静态HTML内容称之为JSP模版元素,在静态的HTML内容之中可以嵌套JSP</div>
                                </li>
                                <li><a href="/article/3231.htm"
                                       title="App Extension编程指南(iOS8/OS X v10.10)中文版" target="_blank">App Extension编程指南(iOS8/OS X v10.10)中文版</a>
                                    <span class="text-muted">啸笑天</span>
<a class="tag" taget="_blank" href="/search/ext/1.htm">ext</a>
                                    <div>  
  
  
  
 当iOS 8.0和OS X v10.10发布后,一个全新的概念出现在我们眼前,那就是应用扩展。顾名思义,应用扩展允许开发者扩展应用的自定义功能和内容,能够让用户在使用其他app时使用该项功能。你可以开发一个应用扩展来执行某些特定的任务,用户使用该扩展后就可以在多个上下文环境中执行该任务。比如说,你提供了一个能让用户把内容分</div>
                                </li>
                                <li><a href="/article/3358.htm"
                                       title="SQLServer实现无限级树结构" target="_blank">SQLServer实现无限级树结构</a>
                                    <span class="text-muted">macroli</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/SQL+Server/1.htm">SQL Server</a>
                                    <div> 
 表结构如下: 
 数据库id path titlesort 排序 1 0 首页 0 2 0,1 新闻 1 3 0,2 JAVA 2 4 0,3 JSP 3 5 0,2,3 业界动态 2 6 0,2,3 国内新闻 1 
 创建一个存储过程来实现,如果要在页面上使用可以设置一个返回变量将至传过去 
   
 create procedure test
as
begin
decla</div>
                                </li>
                                <li><a href="/article/3485.htm"
                                       title="Css居中div,Css居中img,Css居中文本,Css垂直居中div" target="_blank">Css居中div,Css居中img,Css居中文本,Css垂直居中div</a>
                                    <span class="text-muted">qiaolevip</span>
<a class="tag" taget="_blank" href="/search/%E4%BC%97%E8%A7%82%E5%8D%83%E8%B1%A1/1.htm">众观千象</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E6%B0%B8%E6%97%A0%E6%AD%A2%E5%A2%83/1.htm">学习永无止境</a><a class="tag" taget="_blank" href="/search/%E6%AF%8F%E5%A4%A9%E8%BF%9B%E6%AD%A5%E4%B8%80%E7%82%B9%E7%82%B9/1.htm">每天进步一点点</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a>
                                    <div>/**********Css居中Div**********/
div.center {
  width: 100px;
  margin: 0 auto;
}
/**********Css居中img**********/
img.center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

</div>
                                </li>
                                <li><a href="/article/3612.htm"
                                       title="Oracle 常用操作(实用)" target="_blank">Oracle 常用操作(实用)</a>
                                    <span class="text-muted">吃猫的鱼</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a>
                                    <div> 
  SQL>select text from all_source where owner=user and name=upper('&plsql_name');
  SQL>select * from user_ind_columns where index_name=upper('&index_name');  将表记录恢复到指定时间段以前</div>
                                </li>
                                <li><a href="/article/3739.htm"
                                       title="iOS中使用RSA对数据进行加密解密" target="_blank">iOS中使用RSA对数据进行加密解密</a>
                                    <span class="text-muted">witcheryne</span>
<a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/rsa/1.htm">rsa</a><a class="tag" taget="_blank" href="/search/iPhone/1.htm">iPhone</a><a class="tag" taget="_blank" href="/search/objective+c/1.htm">objective c</a>
                                    <div>  
RSA算法是一种非对称加密算法,常被用于加密数据传输.如果配合上数字摘要算法, 也可以用于文件签名. 
本文将讨论如何在iOS中使用RSA传输加密数据. 本文环境 
 
 mac os  
 openssl-1.0.1j, openssl需要使用1.x版本, 推荐使用[homebrew](http://brew.sh/)安装. 
 Java 8 
 RSA基本原理 
RS</div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>