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/1891139692934524928.htm"
                           title="vue点击左边导航,右边出现页面步骤" target="_blank">vue点击左边导航,右边出现页面步骤</a>
                        <span class="text-muted">胡桃不是夹子</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>vue点击左边导航,右边出现页面步骤一定要import不然会出错index.jsCourse作为Homeview子路由Homeview加入点击跳转父Homeview中有RouterView(路由出口,跳转至相应路径)和RouterLink(点击跳转)跳转的页面都为Homeview子只有为el-menu-item标签时,index才会和default-active配对生效高亮:default-act</div>
                    </li>
                    <li><a href="/article/1891138936043008000.htm"
                           title="基于deepseek api和openweather 天气API实现Function Calling技术讲解" target="_blank">基于deepseek api和openweather 天气API实现Function Calling技术讲解</a>
                        <span class="text-muted">匹马夕阳</span>
<a class="tag" taget="_blank" href="/search/AI%E6%8A%80%E6%9C%AF/1.htm">AI技术</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>以下是一个结合DeepSeekAPI和OpenWeatherAPI的完整FunctionCalling示例,包含意图识别、API调用和结果整合:importrequestsimportjsonimportos#配置API密钥(从环境变量获取)DEEPSEEK_API_KEY=os.getenv("DEEPSEEK_API_KEY")OPENWEATHER_API_KEY=os.getenv("OP</div>
                    </li>
                    <li><a href="/article/1891124437206495232.htm"
                           title="Linux(WSL/Ubuntu)vscode配置C++调试环境与相关问题" target="_blank">Linux(WSL/Ubuntu)vscode配置C++调试环境与相关问题</a>
                        <span class="text-muted">力行128</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/ubuntu/1.htm">ubuntu</a><a class="tag" taget="_blank" href="/search/vscode/1.htm">vscode</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a>
                        <div>步骤:先cmake编译得到可执行的二进制文件,将生成的二进制文件添加到launch.json的"program":处。可用的json文件如下,根据自己程序更改:tasks.json(编译器构建设置)launch.json(调试器设置)c_cpp_properties.json(编译器路径和IntelliSense设置)1.launch.json注:需要将可执行文件填到launch的program处</div>
                    </li>
                    <li><a href="/article/1891115228079386624.htm"
                           title="李志军老师操作系统实验" target="_blank">李志军老师操作系统实验</a>
                        <span class="text-muted">JHFeng_white&black</span>
<a class="tag" taget="_blank" href="/search/ubuntu/1.htm">ubuntu</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a>
                        <div>李志军老师操作系统实验_环境搭建准备工作宿主机:macOSMonterey12.2.1虚拟机:我选择的虚拟机是vmwarefusionpro(之前用的是免费版本的vmwarefusion,但是安装了ubuntu后发现始终安装不了vmwaretools)ubuntu18.04.6,这里附上我的网盘链接链接:https://pan.baidu.com/s/1bHpi-PWaqJSUAM_7BXPaLQ</div>
                    </li>
                    <li><a href="/article/1891106017551380480.htm"
                           title="使用Wiki.js配置LDAP认证的编程学习" target="_blank">使用Wiki.js配置LDAP认证的编程学习</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%AD%A6%E4%B9%A0/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/%E7%BC%96%E7%A8%8B%E5%AD%A6%E4%B9%A0/1.htm">编程学习</a>
                        <div>在本文中,我们将探讨如何使用Wiki.js配置LDAP认证。LDAP(轻量级目录访问协议)是一种常用的用于身份验证和授权的协议,它可以让我们将用户凭据存储在中央目录服务器上,以便在不同的应用程序中进行身份验证。Wiki.js是一款功能强大的开源知识管理和文档协作平台,它提供了许多扩展功能,其中之一就是支持LDAP认证。通过配置LDAP认证,我们可以让用户使用他们在LDAP服务器上的凭据登录Wiki</div>
                    </li>
                    <li><a href="/article/1891103243744899072.htm"
                           title="建筑物损坏程度分割数据集labelme格式2816张5类别" target="_blank">建筑物损坏程度分割数据集labelme格式2816张5类别</a>
                        <span class="text-muted">FL1623863129</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E9%9B%86/1.htm">数据集</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a>
                        <div>数据集格式:labelme格式(不包含mask文件,仅仅包含jpg图片和对应的json文件)图片数量(jpg文件个数):2816标注数量(json文件个数):2816标注类别数:5标注类别名称:["minor-damage","destroyed","un-classified","major-damage","no-damage"]每个类别标注的框数:minor-damagecount=1371</div>
                    </li>
                    <li><a href="/article/1891102487805489152.htm"
                           title="Wiki.js 集成 Artalk 评论系统配置指南" target="_blank">Wiki.js 集成 Artalk 评论系统配置指南</a>
                        <span class="text-muted">运维小弟| srebro.cn</span>
<a class="tag" taget="_blank" href="/search/%E7%9F%A5%E8%AF%86%E5%BA%93/1.htm">知识库</a><a class="tag" taget="_blank" href="/search/%E7%9F%A5%E8%AF%86%E5%BA%93/1.htm">知识库</a><a class="tag" taget="_blank" href="/search/wiki.js/1.htm">wiki.js</a><a class="tag" taget="_blank" href="/search/wikijs/1.htm">wikijs</a>
                        <div>Wiki.js集成Artalk评论系统配置指南一、Artalk核心优势开源性质采用MIT许可证的自托管评论系统,支持全平台集成数据控制评论数据存储在自有服务器,避免第三方服务依赖轻量化架构Go语言开发的后端服务,内存占用低于50MB二、DockerCompose部署方案部署文件docker-compose.yamlversion:'3.8'services:artalk:image:artalk/</div>
                    </li>
                    <li><a href="/article/1891101604044664832.htm"
                           title="Vue 2 路由指南:从基础到高级" target="_blank">Vue 2 路由指南:从基础到高级</a>
                        <span class="text-muted">鸡吃丸子</span>
<a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</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%E6%A1%86%E6%9E%B6/1.htm">前端框架</a>
                        <div>注意:对于代码看不清的部分,用鼠标选中就能看到了,背景颜色和字体颜色过于接近,我也不知道怎么调,只能这样子先看着了一、VueRouter是什么?VueRouter是Vue.js官方的路由管理器,它允许你在单页面应用中通过不同的URL显示不同的组件。VueRouter与Vue.js核心深度集成,提供了声明式的路由定义、嵌套路由、动态路由、导航守卫等功能,帮助开发者构建复杂的单页面应用。二、安装与配置</div>
                    </li>
                    <li><a href="/article/1891091015947841536.htm"
                           title="根据deepseek模型微调训练自动驾驶模型及数据集的思路" target="_blank">根据deepseek模型微调训练自动驾驶模型及数据集的思路</a>
                        <span class="text-muted">ywfwyht</span>
<a class="tag" taget="_blank" href="/search/%E8%87%AA%E5%8A%A8%E9%A9%BE%E9%A9%B6/1.htm">自动驾驶</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E8%87%AA%E5%8A%A8%E9%A9%BE%E9%A9%B6/1.htm">自动驾驶</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a>
                        <div>以下是使用DeepSeek模型微调训练自动驾驶模型的详细步骤和代码示例。本流程假设你已有自动驾驶领域的数据集(如驾驶指令、传感器数据等),并基于PyTorch框架实现。Step1:环境准备#安装依赖库pipinstalltorchtransformersdatasetsnumpypandasStep2:数据准备假设数据集格式为JSON,包含输入文本(传感器/场景描述)和输出控制指令://data/</div>
                    </li>
                    <li><a href="/article/1891089498368962560.htm"
                           title="使用 MySQL 从 JSON 字符串提取数据" target="_blank">使用 MySQL 从 JSON 字符串提取数据</a>
                        <span class="text-muted">m0_66323401</span>
<a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/1.htm">学习路线</a><a class="tag" taget="_blank" href="/search/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4/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><a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a>
                        <div>使用MySQL从JSON字符串提取数据在现代数据库管理中,JSON格式因其灵活性而广泛使用。然而,当数据存储在JSON中时,我们经常需要将其转换为更易于处理的格式。本篇文章将通过一个具体的SQL查询示例,展示如何从存储在MySQL中的JSON字符串提取数据并重新格式化。1.背景知识JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器</div>
                    </li>
                    <li><a href="/article/1891078912692252672.htm"
                           title="Flux架构:构建可预测的Web应用状态管理体系" target="_blank">Flux架构:构建可预测的Web应用状态管理体系</a>
                        <span class="text-muted">阿珊和她的猫</span>
<a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>前端开发工程师、技术日更博主、已过CET6阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1牛客高级专题作者、打造专栏《前端面试必备》、《2024面试高频手撕题》蓝桥云课签约作者、上架课程《Vue.js和Egg.js开发企业级健康管理项目》、《带你从入门到实战全面掌握uni-app》前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。文章</div>
                    </li>
                    <li><a href="/article/1891065799469232128.htm"
                           title="探索 Elm 的 Material Design 组件库:elm-mdl" target="_blank">探索 Elm 的 Material Design 组件库:elm-mdl</a>
                        <span class="text-muted">薄垚宝</span>

                        <div>探索Elm的MaterialDesign组件库:elm-mdlelm-mdlElm-portoftheMaterialDesignLiteCSS/JSlibrary项目地址:https://gitcode.com/gh_mirrors/el/elm-mdl项目介绍elm-mdl是一个基于Elm语言的MaterialDesign组件库,它是对Google的MaterialDesignLite库的El</div>
                    </li>
                    <li><a href="/article/1891065672667033600.htm"
                           title="探索Redux:构建可预测、可测试的JavaScript应用" target="_blank">探索Redux:构建可预测、可测试的JavaScript应用</a>
                        <span class="text-muted">黎杉娜Torrent</span>

                        <div>探索Redux:构建可预测、可测试的JavaScript应用learn-redux:boom:ComprehensiveNotesforLearning(howtouse)ReduxtomanagestateinyourWeb/Mobile(React.js)Apps.项目地址:https://gitcode.com/gh_mirrors/le/learn-redux项目介绍在现代Web开发中,J</div>
                    </li>
                    <li><a href="/article/1891054457932804096.htm"
                           title="[失业前端恶补算法]JavaScript leetcode刷题top100(六):字母异位词分组、最长连续序列、找到字符串中所有字母异位词、最大子数组和、除自身以外数组的乘积" target="_blank">[失业前端恶补算法]JavaScript leetcode刷题top100(六):字母异位词分组、最长连续序列、找到字符串中所有字母异位词、最大子数组和、除自身以外数组的乘积</a>
                        <span class="text-muted">摸鱼老萌新</span>
<a class="tag" taget="_blank" href="/search/%E5%A4%B1%E4%B8%9A%E5%89%8D%E7%AB%AF%E6%81%B6%E8%A1%A5%E7%AE%97%E6%B3%95/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/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/1.htm">动态规划</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%93%88%E5%B8%8C/1.htm">哈希</a>
                        <div>专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷49.字母异位词分组题面给你一个字符串数组,请你将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词是由重新排列源单词的所有字母得到的一个新单词。知识点:哈希表、排序思路这里用了js语言的一个小技巧,我们可以使用split这个api将字符串变成字符的数组,之后我们对得到的数组进行排序,这样字母异位词得到了结果字符串的一致的,</div>
                    </li>
                    <li><a href="/article/1891044744973316096.htm"
                           title="Vue.js 新手必看:5个趣味小案例快速理解数据绑定原理" target="_blank">Vue.js 新手必看:5个趣味小案例快速理解数据绑定原理</a>
                        <span class="text-muted">云资社</span>
<a class="tag" taget="_blank" href="/search/VUE/1.htm">VUE</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>Vue.js是一个渐进式JavaScript框架,用于构建用户界面。其核心特性之一是数据绑定,它允许开发者通过简单的声明式语法将数据与DOM元素绑定在一起。这种双向数据绑定机制使得数据更新和视图更新变得非常直观和高效。本文将通过5个趣味小案例,帮助Vue.js新手快速理解数据绑定的原理和实现方式。案例1:简单的文本绑定目标将输入框中的内容实时显示在页面上。实现代码Vue数据绑定-文本绑定输入框内容</div>
                    </li>
                    <li><a href="/article/1891032136526393344.htm"
                           title="AWS上基于Llama 3模型检测Amazon Redshift里文本数据的语法和语义错误的设计方案" target="_blank">AWS上基于Llama 3模型检测Amazon Redshift里文本数据的语法和语义错误的设计方案</a>
                        <span class="text-muted">weixin_30777913</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E4%BB%93%E5%BA%93/1.htm">数据仓库</a><a class="tag" taget="_blank" href="/search/%E4%BA%91%E8%AE%A1%E7%AE%97/1.htm">云计算</a><a class="tag" taget="_blank" href="/search/aws/1.htm">aws</a><a class="tag" taget="_blank" href="/search/llama/1.htm">llama</a>
                        <div>一、技术栈选型核心服务:AmazonRedshift:存储原始文本和检测结果AmazonBedrock:托管Llama370B模型AWSLambda:无服务计算(Python运行时)AmazonS3:中间数据存储AWSStepFunctions:工作流编排辅助工具:psycopg2:RedshiftPython连接器boto3:AWSSDKforPythonPandas:数据批处理JSONSche</div>
                    </li>
                    <li><a href="/article/1891032135620423680.htm"
                           title="java获取服务器状态_获取远程服务器上 Java 进程的运行状态" target="_blank">java获取服务器状态_获取远程服务器上 Java 进程的运行状态</a>
                        <span class="text-muted">夏种子</span>
<a class="tag" taget="_blank" href="/search/java%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%8A%B6%E6%80%81/1.htm">java获取服务器状态</a>
                        <div>为了安全考虑,有些服务器会被限制登录.本文介绍如何获取远程服务器上Java进程的运行状态.启动jstatd服务在服务器端启动jstatd服务后,远程的机器可以通过rmi协议获取服务器上Java程序的运行状态.在服务器上创建jstatd的授权文件,假设文件路径为/etc/jstatd.all.policy,内容如下:grantcodebase"file:/usr/local/java/lib/too</div>
                    </li>
                    <li><a href="/article/1891031883022659584.htm"
                           title="面试官 :Java 调优经验有吗?" target="_blank">面试官 :Java 调优经验有吗?</a>
                        <span class="text-muted">Think_Higher</span>
<a class="tag" taget="_blank" href="/search/Java%E7%94%9F%E6%80%81%E5%9C%88/1.htm">Java生态圈</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E4%B8%ADIT%E4%BC%81%E4%B8%9A%E9%9D%A2%E8%AF%95%E9%A2%98%E6%95%B4%E7%90%86/1.htm">大中IT企业面试题整理</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><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/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>文章目录调优准备性能分析CPU分析jstack[pid]jstat-gcutil[pid]vmstat15内存分析IO分析1.文件IO2.网络IO其他分析工具JavaMissionControl(jmc)BtraceJwebap性能调优CPU调优内存调优IO调优其他优化建议JVM参数进阶对于调优这个事情来说,一般就是三个过程:性能监控:问题没有发生,你并不知道你需要调优什么?此时需要一些系统、应用</div>
                    </li>
                    <li><a href="/article/1891030496700329984.htm"
                           title="Java 程序GC机制及性能稳定性调优分析" target="_blank">Java 程序GC机制及性能稳定性调优分析</a>
                        <span class="text-muted">shines_m</span>
<a class="tag" taget="_blank" href="/search/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/1.htm">性能测试</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</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%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/1.htm">压力测试</a>
                        <div>一、JVM资源监控工具1.jvisualVM工具VisualVM提供了一个可视界面,能够监控线程,内存情况,查看方法的CPU时间和内存中的对象,已被GC的对象;在JDK_HOME/bin目录下,双击jvisualvm.exe文件即可打开运行。打开后默认会监控本地运行的java程序,运行的界面如下:2.连接远程服务器,需要在被监控JVM服务器上启动jstatd服务JVMjstatDaemon:守护进</div>
                    </li>
                    <li><a href="/article/1891030370376282112.htm"
                           title="django上传文件" target="_blank">django上传文件</a>
                        <span class="text-muted">大得369</span>
<a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/sqlite/1.htm">sqlite</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a>
                        <div>1、settings.py配置#静态文件配置STATIC_URL='/static/'STATICFILES_DIRS=[BASE_DIR/'static',]上传文件#定义一个视图函数,该函数接收一个request参数fromdjango.shortcutsimportrender#必备引入importjsonfromdjango.views.decorators.httpimportrequi</div>
                    </li>
                    <li><a href="/article/1891025581584216064.htm"
                           title="JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用" target="_blank">JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用</a>
                        <span class="text-muted">霸道流氓气质</span>
<a class="tag" taget="_blank" href="/search/Java%E8%BF%9B%E9%98%B6/1.htm">Java进阶</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>场景记录JVM中常用工具。jps:虚拟机进程状态工具jps(JVMProcessStatusTool):虚拟机进程状态工具,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(MainClass,main()函数所在的类)的名称,以及这些进程的本地虚拟机的唯一ID。命令格式:jps[options][hostid]示例:jps-l选项:-q只输出LVMID,省略主类的名称-m输出虚拟机进程启动时传</div>
                    </li>
                    <li><a href="/article/1891023562173640704.htm"
                           title="go语言获取机器的进程和进程运行参数 获取当前进程的jmx端口 go调用/jstat获取当前Java进程gc情况" target="_blank">go语言获取机器的进程和进程运行参数 获取当前进程的jmx端口 go调用/jstat获取当前Java进程gc情况</a>
                        <span class="text-muted">march of Time</span>
<a class="tag" taget="_blank" href="/search/go/1.htm">go</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a>
                        <div>这里主要分享go中获取机器进程和进程参数的一些代码获取当前机器所有的pid:import"github.com/shirou/gopsutil/process"pids,err:=process.Pids()for_,pid:=rangepids{proc,err:=process.NewProcess(pid)iferr!=nil{log.Errorf("getpid%dinfoerror:%s</div>
                    </li>
                    <li><a href="/article/1891021921319972864.htm"
                           title="深入理解现代前端框架:Vue.js 的进阶探秘" target="_blank">深入理解现代前端框架:Vue.js 的进阶探秘</a>
                        <span class="text-muted">lozhyf</span>
<a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/flutter/1.htm">flutter</a>
                        <div>在当今的web开发领域,前端框架如雨后春笋般涌现,而Vue.js凭借其简洁易用和强大的功能,成为了众多开发者的心头好。本文将带领大家深入探索Vue.js的一些进阶特性,帮助你将Vue应用开发提升到新的高度。一、Vue.js的响应式原理Vue.js最核心的特性之一就是其响应式系统。当数据发生变化时,Vue能够自动更新DOM,这一过程是如何实现的呢?Vue.js使用了Object.defineProp</div>
                    </li>
                    <li><a href="/article/1891014732803010560.htm"
                           title="js学习笔记(1)-函数中的this" target="_blank">js学习笔记(1)-函数中的this</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%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a>
                        <div>以下为我个人的学习笔记,是从我自己比较能够理解的方面对this进行的解读,可能会有误解或不够全面。this是什么this在JS中是一个“指针型变量”,它动态指向当前函数的运行环境,即代指当前函数的运行环境。普通函数中的this:谁调用指向谁//全局functioncool(){console.log(this)}cool()//window,相当于window.cool()//函数中的thisva</div>
                    </li>
                    <li><a href="/article/1891000740210601984.htm"
                           title="【VUE】前端工程化与前端工程化与webpack" target="_blank">【VUE】前端工程化与前端工程化与webpack</a>
                        <span class="text-muted">boy快快长大</span>
<a class="tag" taget="_blank" href="/search/VUE/1.htm">VUE</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/webpack/1.htm">webpack</a>
                        <div>前端工程化与webpack1.前端工程化2.webpack的基本使用2.1创建列表隔行变色项目1.前端工程化2.webpack的基本使用2.1创建列表隔行变色项目初始化项目①新建项目空白目录,并运行npminit–y命令,初始化包管理配置文件package.json②新建src源代码目录③新建src->index.html首页和src->index.js脚本文件④初始化首页基本的结构⑤运行npmi</div>
                    </li>
                    <li><a href="/article/1890984481792258048.htm"
                           title="js 使用缓存判断在规定时间内显示一次弹框" target="_blank">js 使用缓存判断在规定时间内显示一次弹框</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/%E7%BC%93%E5%AD%98/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>js使用缓存判断在规定时间内显示一次弹框功能拆分,新用户注册完成登录跳转首页,js根据注册时间判断显示一个新手指引的弹窗,只在注册当天登录且显示一次jQuery(document).ready(function($){getWinnerModalShow()});//新手指引functiongetWinnerModalShow(){varwinnerModal=newbootstrap.Modal</div>
                    </li>
                    <li><a href="/article/1890982335944388608.htm"
                           title="解析浏览器中JavaScript与Native交互原理:以WebGPU为例" target="_blank">解析浏览器中JavaScript与Native交互原理:以WebGPU为例</a>
                        <span class="text-muted">ttod_qzstudio</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><a class="tag" taget="_blank" href="/search/WebGPU/1.htm">WebGPU</a>
                        <div>引言随着Web应用复杂度的提升,开发者对浏览器访问本地硬件能力的需求日益增长。然而,浏览器必须在开放性与安全性之间找到平衡——既不能放任JavaScript(JS)随意操作系统资源,又要为高性能计算、图形渲染等场景提供支持。WebGPU的出现正是这一矛盾的解决方案之一。作为新一代Web图形API,WebGPU允许JS以接近原生(Native)的方式操作GPU,同时严格遵循浏览器的安全模型。本文将结</div>
                    </li>
                    <li><a href="/article/1890977167953686528.htm"
                           title="vue3 使用 highlight" target="_blank">vue3 使用 highlight</a>
                        <span class="text-muted">穿越到未来calc</span>
<a class="tag" taget="_blank" href="/search/%E6%A8%A1%E6%9D%BF/1.htm">模板</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</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.安装:npminstall--savehighlight.jsnpminstall--save@highlightjs/vue-plugin2.main.js中导入:import'highlight.js/styles/atom-one-dark.css'import'highlight.js/lib/common'importhljsVuePluginfrom'@highlightjs/vu</div>
                    </li>
                    <li><a href="/article/1890973886674169856.htm"
                           title="js:highlight.js实现代码的语法高亮" target="_blank">js:highlight.js实现代码的语法高亮</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>
                        <div>highlight.jsSyntaxhighlightingfortheWeb译文:highlight.js为Web突出显示语法文档官网:https://highlightjs.org/文档:https://highlightjs.readthedocs.io/en/latest/index.htmlgithub:https://github.com/highlightjs/highlight.j</div>
                    </li>
                    <li><a href="/article/1890966438739505152.htm"
                           title="在Vue中使用highlight.js代码高亮" target="_blank">在Vue中使用highlight.js代码高亮</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/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/js/1.htm">js</a>
                        <div>代码高亮是在网页开发中常见的需求之一,它可以使代码在页面上以不同的颜色或样式进行突出显示,提高可读性。highlight.js是一个流行的JavaScript库,它提供了丰富的语法高亮功能,支持多种编程语言和模板语言。本文将介绍如何在Vue项目中使用highlight.js来实现代码高亮的效果。步骤1:安装highlight.js首先,我们需要安装highlight.js库。在Vue项目的根目录下</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>