第十六节,异步操作和Async函数

异步操作和Async函数

异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。

ES6诞生以前,异步编程的方法,大概有下面四种。

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise 对象

ES6将JavaScript异步编程带入了一个全新的阶段,ES7的Async函数更是提出了异步编程的终极解决方案。

基本概念

异步

所谓"异步",简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。

比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。

相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。

回调函数

JavaScript语言对异步编程的实现,就是回调函数。所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。它的英语名字callback,直译过来就是"重新调用"。

读取文件进行处理,是这样写的。

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

上面代码中,readFile函数的第二个参数,就是回调函数,也就是任务的第二段。等到操作系统返回了/etc/passwd这个文件以后,回调函数才会执行。

一个有趣的问题是,为什么Node.js约定,回调函数的第一个参数,必须是错误对象err(如果没有错误,该参数就是null)?原因是执行分成两段,在这两段之间抛出的错误,程序无法捕捉,只能当作参数,传入第二段。

Promise

回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。假定读取A文件之后,再读取B文件,代码如下。

fs.readFile(fileA, function (err, data) {
  fs.readFile(fileB, function (err, data) {
    // ...
  });
});

不难想象,如果依次读取多个文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。这种情况就称为"回调函数地狱"(callback hell)。

Promise就是为了解决这个问题而提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的嵌套,改成链式调用。采用Promise,连续读取多个文件,写法如下。

var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function(data){
  console.log(data.toString());
})
.then(function(){
  return readFile(fileB);
})
.then(function(data){
  console.log(data.toString());
})
.catch(function(err) {
  console.log(err);
});

上面代码中,我使用了fs-readfile-promise模块,它的作用就是返回一个Promise版本的readFile函数。Promise提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。

可以看到,Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。

Promise 的最大问题是代码冗余,原来的任务被Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。

那么,有没有更好的写法呢?

Generator函数

协程

传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案)。其中有一种叫做"协程"(coroutine),意思是多个线程互相协作,完成异步任务。

协程有点像函数,又有点像线程。它的运行流程大致如下。

  • 第一步,协程A开始执行。
  • 第二步,协程A执行到一半,进入暂停,执行权转移到协程B。
  • 第三步,(一段时间后)协程B交还执行权。
  • 第四步,协程A恢复执行。

上面流程的协程A,就是异步任务,因为它分成两段(或多段)执行。

举例来说,读取文件的协程写法如下。

function *asyncJob() {
  // ...其他代码
  var f = yield readFile(fileA);
  // ...其他代码
}

上面代码的函数asyncJob是一个协程,它的奥妙就在其中的yield命令。它表示执行到此处,执行权将交给其他协程。也就是说,yield命令是异步两个阶段的分界线。

协程遇到yield命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。它的最大优点,就是代码的写法非常像同步操作,如果去除yield命令,简直一模一样。

Generator函数的概念

Generator函数是协程在ES6的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。Generator函数的执行方法如下。

function* gen(x){
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

上面代码中,调用Generator函数,会返回一个内部指针(即遍历器)g 。这是Generator函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。调用指针g的next方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的yield语句,上例是执行到x + 2为止。

换言之,next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示Generator函数是否执行完毕,即是否还有下一个阶段。

Generator函数的数据交换和错误处理

Generator函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。

next方法返回值的value属性,是Generator函数向外输出数据;next方法还可以接受参数,这是向Generator函数体内输入数据。

function* gen(x){
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }

上面代码中,第一个next方法的value属性,返回表达式x + 2的值(3)。第二个next方法带有参数2,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量y接收。因此,这一步的 value 属性,返回的就是2(变量y的值)。

Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw('出错了');
// 出错了

上面代码的最后一行,Generator函数体外,使用指针对象的throw方法抛出的错误,可以被函数体内的try ...catch代码块捕获。这意味着,出错的代码与处理错误的代码,实现了时间和空间上的分离,这对于异步编程无疑是很重要的。

异步任务的封装

下面看看如何使用 Generator 函数,执行一个真实的异步任务。

var fetch = require('node-fetch');

function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

上面代码中,Generator函数封装了一个异步操作,该操作先读取一个远程接口,然后从JSON格式的数据解析信息。就像前面说过的,这段代码非常像同步操作,除了加上了yield命令。

执行这段代码的方法如下。

var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});

上面代码中,首先执行Generator函数,获取遍历器对象,然后使用next 方法(第二行),执行异步任务的第一阶段。由于Fetch模块返回的是一个Promise对象,因此要用then方法调用下一个next 方法。

可以看到,虽然 Generator 函数将异步操作表示得很简洁,但是流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。

Thunk函数

参数的求值策略

Thunk函数早在上个世纪60年代就诞生了。

那时,编程语言刚刚起步,计算机学家还在研究,编译器怎么写比较好。一个争论的焦点是"求值策略",即函数的参数到底应该何时求值。

var x = 1;

function f(m){
  return m * 2;
}

f(x + 5)

上面代码先定义函数f,然后向它传入表达式x + 5。请问,这个表达式应该何时求值?

一种意见是"传值调用"(call by value),即在进入函数体之前,就计算x + 5的值(等于6),再将这个值传入函数f 。C语言就采用这种策略。

f(x + 5)
// 传值调用时,等同于
f(6)

另一种意见是"传名调用"(call by name),即直接将表达式x + 5传入函数体,只在用到它的时候求值。Haskell语言采用这种策略。

f(x + 5)
// 传名调用时,等同于
(x + 5) * 2

传值调用和传名调用,哪一种比较好?回答是各有利弊。传值调用比较简单,但是对参数求值的时候,实际上还没用到这个参数,有可能造成性能损失。

function f(a, b){
  return b;
}

f(3 * x * x - 2 * x - 1, x);

上面代码中,函数f的第一个参数是一个复杂的表达式,但是函数体内根本没用到。对这个参数求值,实际上是不必要的。因此,有一些计算机学家倾向于"传名调用",即只在执行时求值。

Thunk函数的含义

编译器的"传名调用"实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做Thunk函数。

function f(m){
  return m * 2;
}

f(x + 5);

// 等同于

var thunk = function () {
  return x + 5;
};

function f(thunk){
  return thunk() * 2;
}

上面代码中,函数f的参数x + 5被一个函数替换了。凡是用到原参数的地方,对Thunk函数求值即可。

这就是Thunk函数的定义,它是"传名调用"的一种实现策略,用来替换某个表达式。

JavaScript语言的Thunk函数

JavaScript语言是传值调用,它的Thunk函数含义有所不同。在JavaScript语言中,Thunk函数替换的不是表达式,而是多参数函数,将其替换成单参数的版本,且只接受回调函数作为参数。

// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);

// Thunk版本的readFile(单参数版本)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);

var Thunk = function (fileName){
  return function (callback){
    return fs.readFile(fileName, callback);
  };
};

上面代码中,fs模块的readFile方法是一个多参数函数,两个参数分别为文件名和回调函数。经过转换器处理,它变成了一个单参数函数,只接受回调函数作为参数。这个单参数版本,就叫做Thunk函数。

任何函数,只要参数有回调函数,就能写成Thunk函数的形式。下面是一个简单的Thunk函数转换器。

// ES5版本
var Thunk = function(fn){
  return function (){
    var args = Array.prototype.slice.call(arguments);
    return function (callback){
      args.push(callback);
      return fn.apply(this, args);
    }
  };
};

// ES6版本
var Thunk = function(fn) {
  return function (...args) {
    return function (callback) {
      return fn.call(this, ...args, callback);
    }
  };
};

使用上面的转换器,生成fs.readFile的Thunk函数。

var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);

下面是另一个完整的例子。

function f(a, cb) {
  cb(a);
}
let ft = Thunk(f);

let log = console.log.bind(console);
ft(1)(log) // 1

Thunkify模块

生产环境的转换器,建议使用Thunkify模块。

首先是安装。

$ npm install thunkify

使用方式如下。

var thunkify = require('thunkify');
var fs = require('fs');

var read = thunkify(fs.readFile);
read('package.json')(function(err, str){
  // ...
});

Thunkify的源码与上一节那个简单的转换器非常像。

function thunkify(fn){
  return function(){
    var args = new Array(arguments.length);
    var ctx = this;

    for(var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }

    return function(done){
      var called;

      args.push(function(){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      });

      try {
        fn.apply(ctx, args);
      } catch (err) {
        done(err);
      }
    }
  }
};

它的源码主要多了一个检查机制,变量called确保回调函数只运行一次。这样的设计与下文的Generator函数相关。请看下面的例子。

function f(a, b, callback){
  var sum = a + b;
  callback(sum);
  callback(sum);
}

var ft = thunkify(f);
var print = console.log.bind(console);
ft(1, 2)(print);
// 3

上面代码中,由于thunkify只允许回调函数执行一次,所以只输出一行结果。

Generator 函数的流程管理

你可能会问, Thunk函数有什么用?回答是以前确实没什么用,但是ES6有了Generator函数,Thunk函数现在可以用于Generator函数的自动流程管理。

Generator函数可以自动执行。

function* gen() {
  // ...
}

var g = gen();
var res = g.next();

while(!res.done){
  console.log(res.value);
  res = g.next();
}

上面代码中,Generator函数gen会自动执行完所有步骤。

但是,这不适合异步操作。如果必须保证前一步执行完,才能执行后一步,上面的自动执行就不可行。这时,Thunk函数就能派上用处。以读取文件为例。下面的Generator函数封装了两个异步操作。

var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);

var gen = function* (){
  var r1 = yield readFile('/etc/fstab');
  console.log(r1.toString());
  var r2 = yield readFile('/etc/shells');
  console.log(r2.toString());
};

上面代码中,yield命令用于将程序的执行权移出Generator函数,那么就需要一种方法,将执行权再交还给Generator函数。

这种方法就是Thunk函数,因为它可以在回调函数里,将执行权交还给Generator函数。为了便于理解,我们先看如何手动执行上面这个Generator函数。

var g = gen();

var r1 = g.next();
r1.value(function(err, data){
  if (err) throw err;
  var r2 = g.next(data);
  r2.value(function(err, data){
    if (err) throw err;
    g.next(data);
  });
});

上面代码中,变量g是Generator函数的内部指针,表示目前执行到哪一步。next方法负责将指针移动到下一步,并返回该步的信息(value属性和done属性)。

仔细查看上面的代码,可以发现Generator函数的执行过程,其实是将同一个回调函数,反复传入next方法的value属性。这使得我们可以用递归来自动完成这个过程。

Thunk函数的自动流程管理

Thunk函数真正的威力,在于可以自动执行Generator函数。下面就是一个基于Thunk函数的Generator执行器。

function run(fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);
    if (result.done) return;
    result.value(next);
  }

  next();
}

function* g() {
  // ...
}

run(g);

上面代码的run函数,就是一个Generator函数的自动执行器。内部的next函数就是Thunk的回调函数。next函数先将指针移到Generator函数的下一步(gen.next方法),然后判断Generator函数是否结束(result.done属性),如果没结束,就将next函数再传入Thunk函数(result.value属性),否则就直接退出。

有了这个执行器,执行Generator函数方便多了。不管内部有多少个异步操作,直接把Generator函数传入run函数即可。当然,前提是每一个异步操作,都要是Thunk函数,也就是说,跟在yield命令后面的必须是Thunk函数。

var g = function* (){
  var f1 = yield readFile('fileA');
  var f2 = yield readFile('fileB');
  // ...
  var fn = yield readFile('fileN');
};

run(g);

上面代码中,函数g封装了n个异步的读取文件操作,只要执行run函数,这些操作就会自动完成。这样一来,异步操作不仅可以写得像同步操作,而且一行代码就可以执行。

Thunk函数并不是Generator函数自动执行的唯一方案。因为自动执行的关键是,必须有一种机制,自动控制Generator函数的流程,接收和交还程序的执行权。回调函数可以做到这一点,Promise 对象也可以做到这一点。

co模块

基本用法

co模块是著名程序员TJ Holowaychuk于2013年6月发布的一个小工具,用于Generator函数的自动执行。

比如,有一个Generator函数,用于依次读取两个文件。

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

co模块可以让你不用编写Generator函数的执行器。

var co = require('co');
co(gen);

上面代码中,Generator函数只要传入co函数,就会自动执行。

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

co(gen).then(function (){
  console.log('Generator 函数执行完成');
});

上面代码中,等到Generator函数执行结束,就会输出一行提示。

co模块的原理

为什么co可以自动执行Generator函数?

前面说过,Generator就是一个异步操作的容器。它的自动执行需要一种机制,当异步操作有了结果,能够自动交回执行权。

两种方法可以做到这一点。

(1)回调函数。将异步操作包装成Thunk函数,在回调函数里面交回执行权。

(2)Promise 对象。将异步操作包装成Promise对象,用then方法交回执行权。

co模块其实就是将两种自动执行器(Thunk函数和Promise对象),包装成一个模块。使用co的前提条件是,Generator函数的yield命令后面,只能是Thunk函数或Promise对象。

上一节已经介绍了基于Thunk函数的自动执行器。下面来看,基于Promise对象的自动执行器。这是理解co模块必须的。

基于Promise对象的自动执行

还是沿用上面的例子。首先,把fs模块的readFile方法包装成一个Promise对象。

var fs = require('fs');

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

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

然后,手动执行上面的Generator函数。

var g = gen();

g.next().value.then(function(data){
  g.next(data).value.then(function(data){
    g.next(data);
  });
});

手动执行其实就是用then方法,层层添加回调函数。理解了这一点,就可以写出一个自动执行器。

function run(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run(gen);

上面代码中,只要Generator函数还没执行到最后一步,next函数就调用自身,以此实现自动执行。

co模块的源码

co就是上面那个自动执行器的扩展,它的源码只有几十行,非常简单。

首先,co函数接受Generator函数作为参数,返回一个 Promise 对象。

function co(gen) {
  var ctx = this;

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

在返回的Promise对象里面,co先检查参数gen是否为Generator函数。如果是,就执行该函数,得到一个内部指针对象;如果不是就返回,并将Promise对象的状态改为resolved。

function co(gen) {
  var ctx = this;

  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.call(ctx);
    if (!gen || typeof gen.next !== 'function') return resolve(gen);
  });
}

接着,co将Generator函数的内部指针对象的next方法,包装成onFulfilled函数。这主要是为了能够捕捉抛出的错误。

function co(gen) {
  var ctx = this;

  return new Promise(function(resolve, reject) {
    if (typeof gen === 'function') gen = gen.call(ctx);
    if (!gen || typeof gen.next !== 'function') return resolve(gen);

    onFulfilled();
    function onFulfilled(res) {
      var ret;
      try {
        ret = gen.next(res);
      } catch (e) {
        return reject(e);
      }
      next(ret);
    }
  });
}

最后,就是关键的next函数,它会反复调用自身。

function next(ret) {
  if (ret.done) return resolve(ret.value);
  var value = toPromise.call(ctx, ret.value);
  if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
  return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
    + 'but the following object was passed: "' + String(ret.value) + '"'));
}

上面代码中,next 函数的内部代码,一共只有四行命令。

第一行,检查当前是否为 Generator 函数的最后一步,如果是就返回。

第二行,确保每一步的返回值,是 Promise 对象。

第三行,使用 then 方法,为返回值加上回调函数,然后通过 onFulfilled 函数再次调用 next 函数。

第四行,在参数不符合要求的情况下(参数非 Thunk 函数和 Promise 对象),将 Promise 对象的状态改为 rejected,从而终止执行。

处理并发的异步操作

co支持并发的异步操作,即允许某些操作同时进行,等到它们全部完成,才进行下一步。

这时,要把并发的操作都放在数组或对象里面,跟在yield语句后面。

// 数组的写法
co(function* () {
  var res = yield [
    Promise.resolve(1),
    Promise.resolve(2)
  ];
  console.log(res);
}).catch(onerror);

// 对象的写法
co(function* () {
  var res = yield {
    1: Promise.resolve(1),
    2: Promise.resolve(2),
  };
  console.log(res);
}).catch(onerror);

下面是另一个例子。

co(function* () {
  var values = [n1, n2, n3];
  yield values.map(somethingAsync);
});

function* somethingAsync(x) {
  // do something async
  return y
}

上面的代码允许并发三个somethingAsync异步操作,等到它们全部完成,才会进行下一步。

async函数

含义

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

async函数是什么?一句话,async函数就是 Generator 函数的语法糖。前文有一个 Generator 函数,依次读取两个文件。

var fs = require('fs');

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

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

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

var asyncReadFile = async function (){
  var f1 = await readFile('/etc/fstab');
  var 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函数的执行,与普通函数一模一样,只要一行。

var result = 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函数的语法规则总体上比较简单,难点是错误处理机制。

(1)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: 出错了

(2)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; line-height:24.96px"> 上面代码中,函数<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getTitle</code>内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">then</code>方法里面的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">console.log</code>。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> (3)正常情况下,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令后面是一个 Promise 对象。如果不是,会被转成一个立即<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>的 Promise 对象。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令的参数是数值<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">123</code>,它被转成Promise对象,并立即<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> <code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令后面的Promise对象如果变为<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>状态,则<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>的参数会被<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">catch</code>方法的回调函数接收到。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 注意,上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>语句前面没有<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">return</code>,但是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>方法的参数依然传入了<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">catch</code>方法的回调函数。这里如果在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>前面加上<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">return</code>,效果是一样的。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 只要一个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>语句后面的Promise变为<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>,那么整个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数都会中断执行。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,第二个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>语句是不会执行的,因为第一个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>语句状态变成了<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 为了避免这个问题,可以将第一个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>放在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">try...catch</code>结构里面,这样第二个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>就会执行。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 另一种方法是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>后面的Promise对象再跟一个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">catch</code>方面,处理前面可能出现的错误。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 如果有多个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令,可以统一放在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">try...catch</code>结构中。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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>
    <span class="token keyword" style="color:rgb(102,217,239)">var</span> 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>
    <span class="token keyword" style="color:rgb(102,217,239)">var</span> 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>
    <span class="token keyword" style="color:rgb(102,217,239)">var</span> 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; line-height:24.96px"> (4)如果<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>后面的异步操作出错,那么等同于<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数返回的Promise对象被<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">f</code>执行后,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>后面的Promise对象会抛出一个错误对象,导致<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">catch</code>方法的回调函数被调用,它的参数就是抛出的错误对象。具体的执行机制,可以参考后文的“async函数的实现”。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 防止出错的方法,也是将其放在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">try...catch</code>代码块之中。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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> 
  <h3 id="async函数的实现" class="async函数的实现" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> async函数的实现</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 所有的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数都可以写成上面的第二种形式,其中的 spawn 函数就是自动执行器。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 下面给出<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">spawn</code>函数的实现,基本就是前文自动执行器的翻版。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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>
    <span class="token keyword" style="color:rgb(102,217,239)">var</span> 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)">try</span> <span class="token punctuation" style="color:rgb(248,248,242)">{</span>
        <span class="token keyword" style="color:rgb(102,217,239)">var</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> 
  <h3 id="async-函数的用法" class="async-函数的用法" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> async 函数的用法</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> <code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数返回一个Promise对象,可以使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">then</code>方法添加回调函数。当函数执行的时候,一旦遇到<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 下面是一个例子。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">async <span class="token keyword" style="color:rgb(102,217,239)">function</span> <span class="token function">getStockPriceByName<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>name<span 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)">var</span> symbol <span class="token operator" style="color:rgb(249,38,114)">=</span> await <span class="token function">getStockSymbol<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>name<span 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)">var</span> stockPrice <span class="token operator" style="color:rgb(249,38,114)">=</span> await <span class="token function">getStockPrice<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>symbol<span 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> stockPrice<span 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">getStockPriceByName<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span><span class="token string">'goog'</span><span 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 punctuation" style="color:rgb(248,248,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; line-height:24.96px"> 上面代码是一个获取股票报价的函数,函数前面的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise</code>对象。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 下面的例子,指定多少毫秒后输出一个值。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><span class="token keyword" style="color:rgb(102,217,239)">function</span> <span class="token function">timeout<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>ms<span 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 punctuation" style="color:rgb(248,248,242)">(</span>resolve<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">setTimeout<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>resolve<span class="token punctuation" style="color:rgb(248,248,242)">,</span> ms<span class="token punctuation" style="color:rgb(248,248,242)">)</span><span class="token punctuation" style="color:rgb(248,248,242)">;</span>
  <span class="token punctuation" style="color:rgb(248,248,242)">}</span><span class="token punctuation" style="color:rgb(248,248,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 function">asyncPrint<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>value<span class="token punctuation" style="color:rgb(248,248,242)">,</span> ms<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">timeout<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>ms<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>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">asyncPrint<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 number" style="color:rgb(174,129,255)">50</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; line-height:24.96px"> 上面代码指定50毫秒以后,输出<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">hello world</code>。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> Async函数有多种使用形式。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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">foo<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)">
// 函数表达式
</span>const foo <span class="token operator" style="color:rgb(249,38,114)">=</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 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> obj <span class="token operator" style="color:rgb(249,38,114)">=</span> <span class="token punctuation" style="color:rgb(248,248,242)">{</span> async <span class="token function">foo<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>
obj<span class="token punctuation" style="color:rgb(248,248,242)">.</span><span class="token function">foo<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><span 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)">
// Class 的方法
</span>class <span class="token class-name">Storage</span> <span class="token punctuation" style="color:rgb(248,248,242)">{</span>
  <span class="token function">constructor<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)">this</span><span class="token punctuation" style="color:rgb(248,248,242)">.</span>cachePromise <span class="token operator" style="color:rgb(249,38,114)">=</span> caches<span class="token punctuation" style="color:rgb(248,248,242)">.</span><span class="token function">open<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span><span class="token string">'avatars'</span><span class="token punctuation" style="color:rgb(248,248,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 function">getAvatar<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>name<span class="token punctuation" style="color:rgb(248,248,242)">)</span> <span class="token punctuation" style="color:rgb(248,248,242)">{</span>
    const cache <span class="token operator" style="color:rgb(249,38,114)">=</span> await <span class="token keyword" style="color:rgb(102,217,239)">this</span><span class="token punctuation" style="color:rgb(248,248,242)">.</span>cachePromise<span class="token punctuation" style="color:rgb(248,248,242)">;</span>
    <span class="token keyword" style="color:rgb(102,217,239)">return</span> cache<span class="token punctuation" style="color:rgb(248,248,242)">.</span><span class="token function">match<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span>`<span class="token operator" style="color:rgb(249,38,114)">/</span>avatars<span class="token operator" style="color:rgb(249,38,114)">/</span>$<span class="token punctuation" style="color:rgb(248,248,242)">{</span>name<span class="token punctuation" style="color:rgb(248,248,242)">}</span><span class="token punctuation" style="color:rgb(248,248,242)">.</span>jpg`<span class="token punctuation" style="color:rgb(248,248,242)">)</span><span class="token punctuation" style="color:rgb(248,248,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 storage <span class="token operator" style="color:rgb(249,38,114)">=</span> <span class="token keyword" style="color:rgb(102,217,239)">new</span> <span class="token class-name">Storage</span><span class="token punctuation" style="color:rgb(248,248,242)">(</span><span class="token punctuation" style="color:rgb(248,248,242)">)</span><span class="token punctuation" style="color:rgb(248,248,242)">;</span>
storage<span class="token punctuation" style="color:rgb(248,248,242)">.</span><span class="token function">getAvatar<span class="token punctuation" style="color:rgb(248,248,242)">(</span></span><span class="token string">'jake'</span><span 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>
<span class="token comment" style="color:rgb(117,113,94)">
// 箭头函数
</span>const foo <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><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 id="注意点" class="注意点" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> 注意点</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 第一点,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令后面的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise</code>对象,运行结果可能是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">rejected</code>,所以最好把<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令放在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">try...catch</code>代码块中。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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>
</code></code></pre> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 第二点,多个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getFoo</code>和<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getBar</code>是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getFoo</code>完成以后,才会执行<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getBar</code>,完全可以让它们同时触发。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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; line-height:24.96px"> 上面两种写法,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getFoo</code>和<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">getBar</code>都是同时触发,这样就会缩短程序的执行时间。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 第三点,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令只能用在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数之中,如果用在普通函数,就会报错。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码会报错,因为await用在普通函数之中了。但是,如果将<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">forEach</code>方法的参数改成<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数,也有问题。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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>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; line-height:24.96px"> 上面代码可能不会正常工作,原因是这时三个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">db.post</code>操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for</code>循环。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 如果确实希望多个请求并发执行,可以使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise.all</code>方法。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> ES6将<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>增加为保留字。使用这个词作为标识符,在ES5是合法的,在ES6将抛出SyntaxError。</p> 
  <h3 id="与Promise、Generator的比较" class="与Promise、Generator的比较" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> 与Promise、Generator的比较</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 我们通过一个例子,来看Async函数与Promise、Generator函数的区别。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 假定某个DOM元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 首先是Promise的写法。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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)">var</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)">var</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)">var</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; line-height:24.96px"> 虽然Promise的写法比回调函数的写法大大改进,但是一眼看上去,代码完全都是Promise的API(then、catch等等),操作本身的语义反而不容易看出来。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 接着是Generator函数的写法。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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)">var</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)">var</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; line-height:24.96px"> 上面代码使用Generator函数遍历了每个动画,语义比Promise写法更清晰,用户定义的操作全部都出现在spawn函数的内部。这个写法的问题在于,必须有一个任务运行器,自动执行Generator函数,上面代码的spawn函数就是自动执行器,它返回一个Promise对象,而且必须保证yield语句后面的表达式,必须返回一个Promise。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 最后是Async函数的写法。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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)">var</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)">var</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; line-height:24.96px"> 可以看到Async函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。它将Generator写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。如果使用Generator写法,自动执行器需要用户自己提供。</p> 
  <h3 id="实例:按顺序完成异步操作" class="实例:按顺序完成异步操作" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> 实例:按顺序完成异步操作</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 实际开发中,经常遇到一组异步操作,需要按照顺序完成。比如,依次远程读取一组URL,然后按照读取的顺序输出结果。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> Promise 的写法如下。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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; line-height:24.96px"> 上面代码使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">fetch</code>方法,同时远程读取一组URL。每个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">fetch</code>操作都返回一个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise</code>对象,放入<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">textPromises</code>数组。然后,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reduce</code>方法依次处理每个<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise</code>对象,然后使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">then</code>,将所有<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise</code>对象连起来,因此就可以依次输出结果。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 这种写法不太直观,可读性比较差。下面是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数实现。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码确实大大简化,问题是所有远程操作都是继发。只有前一个URL返回结果,才会去读取下一个URL,这样做效率很差,非常浪费时间。我们需要的是并发发出远程请求。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,虽然<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">map</code>方法的参数是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数,但它是并发执行的,因为只有<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数内部是继发执行,外部不受影响。后面的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for..of</code>循环内部使用了<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>,因此实现了按顺序输出。</p> 
  <h2 id="异步遍历器" class="异步遍历器" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; font-size:18px; border-top-width:2px; border-top-style:solid; border-top-color:rgb(102,102,102); counter-increment:section 1; color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> 异步遍历器</h2> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 《遍历器》一章说过,Iterator 接口是一种数据遍历的协议,只要调用遍历器对象的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法,就会得到一个表示当前成员信息的对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">{value, done}</code>。其中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">value</code>表示当前的数据的值,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">done</code>是一个布尔值,表示遍历是否结束。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 这隐含着规定,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法是同步的,只要调用就必须立刻返回值。也就是说,一旦执行<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法,就必须同步地得到<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">value</code>和<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">done</code>这两方面的信息。这对于同步操作,当然没有问题,但对于异步操作,就不太合适了。目前的解决方法是,Generator函数里面的异步操作,返回一个Thunk函数或者Promise对象,即<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">value</code>属性是一个Thunk函数或者Promise对象,等待以后返回真正的值,而<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">done</code>属性则还是同步产生的。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 目前,有一个提案,为异步操作提供原生的遍历器接口,即<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">value</code>和<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">done</code>这两个属性都是异步产生,这称为”异步遍历器“(Async Iterator)。</p> 
  <h3 id="异步遍历的接口" class="异步遍历的接口" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> 异步遍历的接口</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 异步遍历器的最大的语法特点,就是调用遍历器的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法,返回的是一个Promise对象。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">asyncIterator</code>是一个异步遍历器,调用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法以后,返回一个Promise对象。因此,可以使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">then</code>方法指定,这个Promise对象的状态变为<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>以后的回调函数。回调函数的参数,则是一个具有<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">value</code>和<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">done</code>两个属性的对象,这个跟同步遍历器是一样的。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 我们知道,一个对象的同步遍历器的接口,部署在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Symbol.iterator</code>属性上面。同样地,对象的异步遍历器接口,部署在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Symbol.asyncIterator</code>属性上面。不管是什么样的对象,只要它的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Symbol.asyncIterator</code>属性有值,就表示应该对它进行异步遍历。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 下面是一个异步遍历器的例子。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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> someCollection<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; line-height:24.96px"> 上面代码中,异步遍历器其实返回了两次值。第一次调用的时候,返回一个Promise对象;等到Promise对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>了,再返回一个表示当前数据成员信息的对象。这就是说,异步遍历器与同步遍历器最终行为是一致的,只是会先返回Promise对象,作为中介。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 由于异步遍历器的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法,返回的是一个Promise对象。因此,可以把它放在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令后面。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>处理以后,就不必使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">then</code>方法了。整个流程已经很接近同步处理了。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 注意,异步遍历器的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法是可以连续调用的,不必等到上一步产生的Promise对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>以后再调用。这种情况下,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法会累积起来,自动按照每一步的顺序运行下去。下面是一个例子,把所有的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法放在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">Promise.all</code>方法里面。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 另一种用法是一次性调用所有的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法,然后<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>最后一步操作。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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>
</code></code></pre> 
  <h3 id="for-await---of" class="for-await---of" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> for await...of</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 前面介绍过,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for...of</code>循环用于遍历同步的Iterator接口。新引入的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for await...of</code>循环,则是用于遍历异步的Iterator接口。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">createAsyncIterable()</code>返回一个异步遍历器,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for...of</code>循环自动调用这个遍历器的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法,会得到一个Promise对象。<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>用来处理这个Promise对象,一旦<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>,就把得到的值(<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">x</code>)传入<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for...of</code>的循环体。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 如果<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法返回的Promise对象被<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>,那么就要用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">try...catch</code>捕捉。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 注意,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for await...of</code>循环也可以用于同步遍历器。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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> 
  <h3 id="异步Generator函数" class="异步Generator函数" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> 异步Generator函数</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 就像Generator函数返回一个同步遍历器对象一样,异步Generator函数的作用,是返回一个异步遍历器对象。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 在语法上,异步Generator函数就是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数与Generator函数的结合。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,异步操作前面使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>关键字标明,即<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>后面的操作,应该返回Promise对象。凡是使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">yield</code>关键字的地方,就是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法的停下来的地方,它后面的表达式的值(即<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await file.readLine()</code>的值),会作为<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next()</code>返回对象的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">value</code>属性,这一点是于同步Generator函数一致的。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 可以像下面这样,使用上面代码定义的异步Generator函数。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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>
</code></code></pre> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 异步Generator函数可以与<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for await...of</code>循环结合起来使用。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> <code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">yield</code>命令依然是立刻返回的,但是返回的是一个Promise对象。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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">doSomethingAsync<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> result<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>
</code></code></pre> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 上面代码中,调用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">next</code>方法以后,会在<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">B</code>处暂停执行,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">yield</code>命令立刻返回一个Promise对象。这个Promise对象不同于<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">A</code>处<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>命令后面的那个Promise对象。主要有两点不同,一是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">A</code>处的Promise对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>以后产生的值,会放入<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">result</code>变量;二是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">B</code>处的Promise对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>以后产生的值,是表达式<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">'Result: ' + result</code>的值;二是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">A</code>处的Promise对象一定先于<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">B</code>处的Promise对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">resolve</code>。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 如果异步Generator函数抛出错误,会被Promise对象<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">reject</code>,然后抛出的错误被<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">catch</code>方法捕获。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 注意,普通的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数返回的是一个Promise对象,而异步Generator函数返回的是一个异步Iterator对象。基本上,可以这样理解,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数和异步Generator函数,是封装异步操作的两种方法,都用来达到同一种目的。区别在于,前者自带执行器,后者通过<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for await...of</code>执行,或者自己编写执行器。下面就是一个异步Generator函数的执行器。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,异步Generator函数产生的异步遍历器,会通过<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">while</code>循环自动执行,每当<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await iterator.next()</code>完成,就会进入下一轮循环。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 下面是这个自动执行器的一个使用实例。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 异步Generator函数出现以后,JavaScript就有了四种函数形式:普通函数、<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">async</code>函数、Generator函数和异步Generator函数。请注意区分每种函数的不同之处。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 最后,同步的数据结构,也可以使用异步Generator函数。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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; line-height:24.96px"> 上面代码中,由于没有异步操作,所以也就没有使用<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">await</code>关键字。</p> 
  <h3 id="yield--语句" class="yield--语句" style="margin-top:50px; margin-bottom:0px; padding-top:20px; padding-bottom:0px; border-top-width:1px; border-top-style:dotted; border-top-color:rgb(119,119,119); color:rgb(51,51,51); font-family:Verdana,Arial; line-height:24.96px"> yield* 语句</h3> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> <code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">yield*</code>语句也可以跟一个异步遍历器。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal">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>
  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; line-height:24.96px"> 上面代码中,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">gen2</code>函数里面的<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">result</code>变量,最后的值是<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">2</code>。</p> 
  <p style="color:rgb(51,51,51); font-family:Verdana,Arial; font-size:15.36px; line-height:24.96px"> 与同步Generator函数一样,<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">for await...of</code>循环会展开<code style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(199,37,78); padding-left:3px; padding-right:3px; background:rgb(249,242,244)">yield*</code>。</p> 
  <pre><code class="language-javascript"><code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><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> 
  <div> 
   <code class=" language-javascript" style="font-family:Consolas,'Courier New',Courier,FreeMono,monospace; font-size:0.7rem; color:rgb(166,226,46); direction:ltr; word-spacing:normal; word-break:normal"><span class="token comment" style="color:rgb(117,113,94)"><br> </span></code> 
  </div> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1176980399889395712"></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">你可能感兴趣的:(ECMAScript)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1835154546289111040.htm"
                           title="EcmaScript和JavaScript的区别" target="_blank">EcmaScript和JavaScript的区别</a>
                        <span class="text-muted">每天吃八顿</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>ECMAScript和JavaScript是经常被混淆的两个术语,但实际上它们之间存在一些区别:ECMAScript:ECMAScript(通常缩写为ES,并且有版本号如ES5,ES6和ES7等)是由ECMA国际(EuropeanComputerManufacturersAssociation)制定的一种脚本语言的规范。这个规范定义了语法、命令、数据类型等基本元素。ECMAScript是一种规范,</div>
                    </li>
                    <li><a href="/article/1834710748438294528.htm"
                           title="ES6 中的 Symbol 是什么?" target="_blank">ES6 中的 Symbol 是什么?</a>
                        <span class="text-muted">隐逸王</span>

                        <div>前言记得刚找工作那会,几种数据类型是必问题,当时的答案一般都是七种——字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined),时至今日,某些网络教程上还是这样的分类:不完整的分类其实,随着ECMAScript的发展和完善,在ES6(2015)和ES11(2020)中,又分别增加了Symbol和Bi</div>
                    </li>
                    <li><a href="/article/1834385092659736576.htm"
                           title="ecmascript和javascript的区别?" target="_blank">ecmascript和javascript的区别?</a>
                        <span class="text-muted">2301_79698214</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>ECMAScript是JavaScript的标准规范,而JavaScript是基于ECMAScript规范开发的一种编程语言。简单来说,ECMAScript是一套定义了JavaScript语法和语义的规范,而JavaScript是实际的编程语言。具体来说,ECMAScript是由ECMA(EuropeanComputerManufacturersAssociation,欧洲计算机制造商协会)定义和</div>
                    </li>
                    <li><a href="/article/1833840771829166080.htm"
                           title="Python全栈 part02 - 006 Ajax" target="_blank">Python全栈 part02 - 006 Ajax</a>
                        <span class="text-muted">drfung</span>

                        <div>JSON定义:JSON(Javascriptobjectnotation,JS对象标记)是一种轻量级的数据交换格式;是基于ECMASCript(w3cjs规范)的一个子集.JS-JSON-Python.pngJSON对象定义需要注意的点属性名必须用"(双引号)不能使用十六进制值不能使用undefined不能使用函数名和日期函数stringify与parse方法JSON.parse()将一个JSON</div>
                    </li>
                    <li><a href="/article/1833831169653829632.htm"
                           title="ECMAScript与JavaScript的区别" target="_blank">ECMAScript与JavaScript的区别</a>
                        <span class="text-muted">vvvae1234</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>在现代Web开发中,JavaScript是一种不可或缺的语言,而ECMAScript则是JavaScript的标准化版本。理解二者之间的差异,有助于前端开发者更好地编写高效、可维护的代码。本指南将深入探讨ECMAScript与JavaScript的区别,并通过实际案例演示如何在实际开发中应用这些知识。2.ECMAScript和JavaScript简介2.1什么是JavaScript?JavaScr</div>
                    </li>
                    <li><a href="/article/1833799648578465792.htm"
                           title="web学习笔记11-node.js基础" target="_blank">web学习笔记11-node.js基础</a>
                        <span class="text-muted">晴天.js</span>
<a class="tag" taget="_blank" href="/search/web-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">web-学习笔记</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%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>一、ES6ECMAscript->ES是JS的标准规范ES6是JS的第六套标准规范1,块级作用域let声明的变量,会进入暂时性的死区,提升后暂时不允许访问,只有赋值以后才允许访问let声明的变量不允许重复声明块级作用域:大括号之间的语句块,例如if、else。块级作用域下,let和const声明的局部变量或者常量,不允许被块级作用域以外访问let和const即使声明在全局作用域下,也不是全局变量或</div>
                    </li>
                    <li><a href="/article/1833479296862220288.htm"
                           title="深入探索从ES6到ES2023" target="_blank">深入探索从ES6到ES2023</a>
                        <span class="text-muted">hai40587</span>
<a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>从ES6到ES2023,我们深入探索ECMAScript(简称ES)的演变与发展,了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本,每年都在不断推出新版本,为开发者带来更加丰富和强大的功能。本文将从ES6的引入开始,逐步介绍到最新的ES2023,同时探讨这些新特性对现代Web开发的影响。ECMAScript简介与JavaScript的关</div>
                    </li>
                    <li><a href="/article/1833389679165140992.htm"
                           title="2019-12-18:第五章:引用类型(Object和Arrary)" target="_blank">2019-12-18:第五章:引用类型(Object和Arrary)</a>
                        <span class="text-muted">Lau17</span>

                        <div>引用类型的值是引用类型的实例。在ECMAScript中,引用类型是一种数据结构,它通常将功能于数据组合在一起。有人将他称之为类,但这并不妥当。因为它不具有传统面向对象语言中类所支持的类和接口等基本定义。引用类型经常被称作对象定义。原因是他们描述的是一类对象所具有的属性于方法。一个真正的对象实际上是某个特定引用类型的实例化。对象被new操作符+构造函数创造,再将其赋给一个引用类型的变量。举个例子:v</div>
                    </li>
                    <li><a href="/article/1833314776994902016.htm"
                           title="ECMAScript简介" target="_blank">ECMAScript简介</a>
                        <span class="text-muted">老四点COM</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</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>前言ECMAScript(通常简称为ES)由ECMA国际标准化组织制定的一种脚本语言标准,Netscape最初开发的JavaScript演变而来。ECMAScript为JavaScript提供了基础语言结构和功能。最初设计成一种脚本语言,用来服务Web。作为脚本语言ES同时具备其他脚本语言一样的性质。一、发展历史ECMAScript的历史可以追溯到1995年12月,当时升阳与网景联合推出了Java</div>
                    </li>
                    <li><a href="/article/1833257284948553728.htm"
                           title="ES6至ES2023:深入理解ECMAScript的演变之路" target="_blank">ES6至ES2023:深入理解ECMAScript的演变之路</a>
                        <span class="text-muted">N201871643</span>
<a class="tag" taget="_blank" href="/search/%E7%83%AD%E9%97%A8%E7%9B%B8%E5%85%B3%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/1.htm">热门相关技术分享</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a><a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>ES6至ES2023:深入理解ECMAScript的演变之路目录ES6至ES2023:深入理解ECMAScript的演变之路一、ECMAScript简介二、ES6:里程碑式的版本1.类语法2.模块化3.箭头函数4.承诺5.Set和Map三、ES7至ES12:稳步前进1.ES7(ES2016美)2.ES8(ES2017美)3.ES9(ES2018英)4、ES10(ES2019美)5.ES11(ES2</div>
                    </li>
                    <li><a href="/article/1833214420331884544.htm"
                           title="JSON:轻量级的数据交换格式" target="_blank">JSON:轻量级的数据交换格式</a>
                        <span class="text-muted">Tsingfeng.</span>
<a class="tag" taget="_blank" href="/search/%E5%9F%BA%E7%A1%80%E9%87%8A%E7%96%91/1.htm">基础释疑</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a>
                        <div>JSON(JavaScriptObjectNotation,JS对象简谱)是一种轻量级的数据交换格式。它基于ECMAScript(EuropeanComputerManufacturersAssociation,欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生</div>
                    </li>
                    <li><a href="/article/1832980646503477248.htm"
                           title="JavaScript基础" target="_blank">JavaScript基础</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/javascript/1.htm">javascript</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%89%8D%E7%AB%AF/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/%E7%AC%94%E8%AE%B0/1.htm">笔记</a>
                        <div>1JavaScript介绍1.1JS简介1.JavaScript是一种运行在客户端(浏览器)的编程语言,实现人机交互效果。2.作用——网页特效(监听用户的一些行为,让网页作出对应的反馈,如轮播图、下拉菜单等)——表单验证(针对表单数据的合法性进行判断,如输入邮箱的判断)——数据交互(后台的数据,渲染到前端)——服务端编程(node.js)3.JavaScript的组成ECMAScript:(js的</div>
                    </li>
                    <li><a href="/article/1832723850467569664.htm"
                           title="JavaScript - Api学习 Day1(WebApi、操作DOM对象)" target="_blank">JavaScript - Api学习 Day1(WebApi、操作DOM对象)</a>
                        <span class="text-muted">你会魔法吗✧(≖ ◡ ≖✿)</span>
<a class="tag" taget="_blank" href="/search/HTML%2BCSS%2BJS/1.htm">HTML+CSS+JS</a><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%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>应用编程接口(API)是编程语言中提供的结构,允许开发者更轻松地创建复杂的功能。、webapi是一套操作网页内容(DOM)与浏览器窗口(BOM)的对象Js由ECMAScript、DOM、BOM三个部分组成。文章目录零、前言0.1变量声明壹、WebAPI的认识1.1作用1.2什么是DOM1.3什么是DOM对象主要概念:示例代码:二、获取DOM对象2.1根据CSS选择器获取DOM元素2.1.1`que</div>
                    </li>
                    <li><a href="/article/1832721077667721216.htm"
                           title="ecmascript和javascript的区别 优缺点,使用场景 性能等方面介绍" target="_blank">ecmascript和javascript的区别 优缺点,使用场景 性能等方面介绍</a>
                        <span class="text-muted">大白菜程序猿</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>ECMAScript和JavaScript在Web开发中扮演着重要角色,但它们在定义、特性、使用场景、性能等方面存在明显的区别。以下是对这两者的详细比较:一、定义与性质ECMAScript:ECMAScript是一种由EcmaInternational(欧洲计算机制造商协会)制定的脚本语言规范。它不是一种具体的编程语言,而是一种为各种脚本语言提供统一基础和高层次抽象的规范。ECMAScript定义</div>
                    </li>
                    <li><a href="/article/1832434638535094272.htm"
                           title="Babel 安装、配置和基本使用" target="_blank">Babel 安装、配置和基本使用</a>
                        <span class="text-muted">玄晓乌屋</span>
<a class="tag" taget="_blank" href="/search/js/1.htm">js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/firefox/1.htm">firefox</a><a class="tag" taget="_blank" href="/search/chrome/1.htm">chrome</a>
                        <div>原址Babel安装、配置和基本使用Babel是一款JavaScript编译器,它可以把ECMAScript2015+的代码转译成低版本兼容的代码。作用语法转换:Babel会转译新版本的ES代码,比如箭头函数,解构,模板字符串或者类等。Babel会把这些新语法转译成较低版本的代码。需要注意的是,Babel会把ES模块转化为CommonJS模块,模块转化可以查看此文章。通过Polyfill添加缺失的特</div>
                    </li>
                    <li><a href="/article/1832306161907494912.htm"
                           title="ECMAScript和JavaScript的区别和联系" target="_blank">ECMAScript和JavaScript的区别和联系</a>
                        <span class="text-muted">eqa11</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</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>文章目录ECMAScript和JavaScript的区别和联系一、引言二、ECMAScript与JavaScript的定义1、ECMAScript1.1、历史背景1.2、发展2、JavaScript2.1、实现三、ECMAScript与JavaScript的区别1、规范与实现2、平台限制四、总结ECMAScript和JavaScript的区别和联系一、引言在Web开发的世界中,JavaScript</div>
                    </li>
                    <li><a href="/article/1832253227907772416.htm"
                           title="map跟set的区别和共性" target="_blank">map跟set的区别和共性</a>
                        <span class="text-muted">m0_73882020</span>
<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%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>在JavaScript中,Map和Set是两个用于存储数据的集合类型,它们在用途和行为上有一些重要的区别和共性。共同点都保持插入顺序:Map和Set都维护了元素的插入顺序。你可以使用forEach或for...of迭代它们时,会按照插入的顺序访问元素。都是ES6引入的:两者都是ECMAScript6(ES6)引入的新数据结构,提供了更灵活和强大的数据存储和操作功能。支持迭代:两者都支持使用forE</div>
                    </li>
                    <li><a href="/article/1831898466570301440.htm"
                           title="Qt之Json" target="_blank">Qt之Json</a>
                        <span class="text-muted">信必诺</span>
<a class="tag" taget="_blank" href="/search/Qt/1.htm">Qt</a>
                        <div>Json     JSON是一种轻量级的数据交换格式。它基于ECMAScript的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰、易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 Qt之Json     QT+=core      相关头文件:          QJsonObject          QJsonArray          QJso</div>
                    </li>
                    <li><a href="/article/1831873375480410112.htm"
                           title="ecmascript与javascript的区别是什么?" target="_blank">ecmascript与javascript的区别是什么?</a>
                        <span class="text-muted">cesske</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>ECMAScript与JavaScript之间存在紧密的联系,但也有一些关键的区别。以下是它们之间的主要区别:文章目录前言一、定义与性质二、功能与特性三、示例对比总结前言ECMAScript与JavaScript之间存在紧密的联系,但也有一些关键的区别。以下是它们之间的主要区别:一、定义与性质ECMAScript:是一种标准化的脚本语言规范,由EcmaInternational(欧洲计算机制造商协</div>
                    </li>
                    <li><a href="/article/1831859688954753024.htm"
                           title="js红宝书笔记十 第九章 代理与反射" target="_blank">js红宝书笔记十 第九章 代理与反射</a>
                        <span class="text-muted">合肥黑</span>

                        <div>本文继续对JavaScript高级程序设计第四版第九章代理与反射进行学习ECMAScript6新增的代理和反射为开发者提供了拦截并向基本操作嵌入额外行为的能力。具体地说,可以给目标对象定义一个关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用。在对目标对象的各种操作影响目标对象之前,可以在代理对象中对这些操作加以控制。在ES6之前,ECMAScript中并没有类似代理的特性。由于代理是一种</div>
                    </li>
                    <li><a href="/article/1831781125559775232.htm"
                           title="es6中解构赋值" target="_blank">es6中解构赋值</a>
                        <span class="text-muted">茶卡盐佑星_</span>
<a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>ES6(ECMAScript2015)引入了一种新的表达式——解构赋值(Destructuringassignment),允许你直接从数组或对象中提取数据,赋值给声明的变量。这种方式使得数据提取更加简洁明了。数组解构赋值数组解构赋值允许你从数组中提取值,然后按照你指定的模式对变量进行赋值。基本用法:let[a,b,c]=[1,2,3];console.log(a);//1console.log(b</div>
                    </li>
                    <li><a href="/article/1831702200708067328.htm"
                           title="nodejs笔记总结" target="_blank">nodejs笔记总结</a>
                        <span class="text-muted">是张鱼小丸子鸭</span>
<a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a><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>
                        <div>nodejs的概念:nodejs是一个基于ChromeV8引擎的JavaScript运行环境。Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效。Node.js的包管理器npm,是全球最大的开源库生态系统。node组成:Ecmascript模块模块的分类:内置模块:fshttppathurl自定义模块:commonjs规范第三方模块(npm下载)常见的模块指令:npmnodep</div>
                    </li>
                    <li><a href="/article/1831595047942975488.htm"
                           title="node.js入门基础" target="_blank">node.js入门基础</a>
                        <span class="text-muted">readmancynn</span>
<a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>Node总起Node.js是什么Node.js是JavaScript运行环境,使得JS可以运行在浏览器以外的地方单线程,通过异步的方式来处理并发的问题「浏览器中的JSVSNode.js中的JS」基本语法一致,ECMAScriptNode没有Bom、DomNode环境为JavaScript提供了一些服务器级别的API文件的读写网络通信、http服务构建于Chrome的V8引擎之上引擎:用于解析和执行</div>
                    </li>
                    <li><a href="/article/1831556227981733888.htm"
                           title="ecmascript和javascript的区别" target="_blank">ecmascript和javascript的区别</a>
                        <span class="text-muted">丁爸</span>
<a class="tag" taget="_blank" href="/search/web%E5%89%8D%E7%AB%AF/1.htm">web前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>1.简介1.1.概述1.1.1.ecmascriptECMAScript(简称ES)是JavaScript编程语言的一个标准化版本。它是为网络开发设计的一种轻量级的脚本语言,主要用于在网页上实现交互性和动态效果。ECMAScript是该语言的标准名称,而JavaScript是其最知名和广泛使用的实现。1.1.2.javascriptJavaScript是一种高级编程语言,主要用于网页开发,它使得网</div>
                    </li>
                    <li><a href="/article/1831502386246545408.htm"
                           title="ecmascript和javascript的区别详细讲解" target="_blank">ecmascript和javascript的区别详细讲解</a>
                        <span class="text-muted">程序员小羊!</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</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>大家好,我是程序员小羊!前言:ECMAScript和JavaScript是紧密相关的术语,但它们有着各自明确的定义和用途。要理解它们的区别,首先需要从它们的起源、发展历史、技术架构以及具体应用领域来分析。以下是对它们的详细讲解。一、定义与历史背景1.1JavaScript的诞生与演变JavaScript是一种高级、动态的脚本语言,最初由Netscape通信公司开发。它的诞生背景可以追溯到1995年</div>
                    </li>
                    <li><a href="/article/1830857886494978048.htm"
                           title="ES6-ES13" target="_blank">ES6-ES13</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>一.ES6新特性ECMAScript6.0(简称ES6或ES2015)2015年6月正式发布1.let和const声明常量let和const不允许重复声明变量,var可以let和const声明的变量不会在预解析的时候解析(没有变量提升),var可以let和const声明的变量会被所有代码块限制作用范围,作用域在{}内,var为全局作用域let和const的区别let声明的变量的值可以改变,cons</div>
                    </li>
                    <li><a href="/article/1830180020501442560.htm"
                           title="详解ES6中的类、对象和类的继承" target="_blank">详解ES6中的类、对象和类的继承</a>
                        <span class="text-muted">前端技术营</span>
<a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>在ES6(ECMAScript2015)之前,JavaScript并没有像其他面向对象的编程语言那样的类(class)的概念。相反,它使用了一种基于原型的继承模型来实现面向对象编程。然而,这种模型对于许多开发者来说可能比较难以理解,特别是在与更传统的面向对象语言(如Java或C++)相比较时。为了简化面向对象的编程范式并提供更直观的代码组织方式,ES6引入了类的概念。虽然JavaScript的类实</div>
                    </li>
                    <li><a href="/article/1829971916513964032.htm"
                           title="React教案" target="_blank">React教案</a>
                        <span class="text-muted">涔溪</span>
<a class="tag" taget="_blank" href="/search/react.js/1.htm">react.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/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a>
                        <div>ECMAScript61、ES6简介1.1、什么是ES6ECMAScript6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。1.2、ECMAScript和JavaScript的关系一个常见的问题是,ECMAScript和JavaScript到底是什么关系?要讲</div>
                    </li>
                    <li><a href="/article/1829891507985936384.htm"
                           title="【一文读懂】ECMAScript" target="_blank">【一文读懂】ECMAScript</a>
                        <span class="text-muted">热爱分享的博士僧</span>
<a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>ECMAScript(通常简称为ES)是一种脚本语言的标准规范,由欧洲计算机制造商协会(ECMAInternational)制定。JavaScript是最著名的实现了ECMAScript规范的语言,广泛用于Web开发。ECMAScript定义了语言的核心语法和特性,但不包括任何关于图形界面、网络请求等与平台相关的API,这些通常是JavaScript运行时环境提供的额外功能,例如浏览器中的DOM(</div>
                    </li>
                    <li><a href="/article/1829678071851085824.htm"
                           title="JavaWeb——前端工程化" target="_blank">JavaWeb——前端工程化</a>
                        <span class="text-muted">A_Tai2333333</span>
<a class="tag" taget="_blank" href="/search/JavaWeb/1.htm">JavaWeb</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>一、前端工程化1.什么是前端工程化:前端工程化是使用软件工程的方法来单独解决前端的开发流程中模块化、组件化、规范化、自动化的问题,以提高效率和降低成本。2.前端工程化实现技术栈:ES6+Nodejs+npm+Vite+VUE3+Router+Pinia+Axios+Element-plusECMAScript6:VUE3中大量使用ES6语法;Nodejs:前端项目运行环境npm:依赖下载工具Vit</div>
                    </li>
                                <li><a href="/article/69.htm"
                                       title="对股票分析时要注意哪些主要因素?" target="_blank">对股票分析时要注意哪些主要因素?</a>
                                    <span class="text-muted">会飞的奇葩猪</span>
<a class="tag" taget="_blank" href="/search/%E8%82%A1%E7%A5%A8+%E5%88%86%E6%9E%90+%E4%BA%91%E6%8E%8C%E8%82%A1%E5%90%A7/1.htm">股票 分析 云掌股吧</a>
                                    <div> 
  众所周知,对散户投资者来说,股票技术分析是应战股市的核心武器,想学好股票的技术分析一定要知道哪些是重点学习的,其实非常简单,我们只要记住三个要素:成交量、价格趋势、振荡指标。 
 
    一、成交量 
 
  大盘的成交量状态。成交量大说明市场的获利机会较多,成交量小说明市场的获利机会较少。当沪市的成交量超过150亿时是强市市场状态,运用技术找综合买点较准;</div>
                                </li>
                                <li><a href="/article/196.htm"
                                       title="【Scala十八】视图界定与上下文界定" target="_blank">【Scala十八】视图界定与上下文界定</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/scala/1.htm">scala</a>
                                    <div>Context Bound,上下文界定,是Scala为隐式参数引入的一种语法糖,使得隐式转换的编码更加简洁。 
  
隐式参数 
首先引入一个泛型函数max,用于取a和b的最大值 
  def max[T](a: T, b: T) = {
    if (a > b) a else b
  } 
 因为T是未知类型,只有运行时才会代入真正的类型,因此调用a > </div>
                                </li>
                                <li><a href="/article/323.htm"
                                       title="C语言的分支——Object-C程序设计阅读有感" target="_blank">C语言的分支——Object-C程序设计阅读有感</a>
                                    <span class="text-muted">darkblue086</span>
<a class="tag" taget="_blank" href="/search/apple/1.htm">apple</a><a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6/1.htm">框架</a><a class="tag" taget="_blank" href="/search/cocoa/1.htm">cocoa</a>
                                    <div>自从1972年贝尔实验室Dennis Ritchie开发了C语言,C语言已经有了很多版本和实现,从Borland到microsoft还是GNU、Apple都提供了不同时代的多种选择,我们知道C语言是基于Thompson开发的B语言的,Object-C是以SmallTalk-80为基础的。和C++不同的是,Object C并不是C的超集,因为有很多特性与C是不同的。 
Object-C程序设计这本书</div>
                                </li>
                                <li><a href="/article/450.htm"
                                       title="去除浏览器对表单值的记忆" target="_blank">去除浏览器对表单值的记忆</a>
                                    <span class="text-muted">周凡杨</span>
<a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E8%AE%B0%E5%BF%86/1.htm">记忆</a><a class="tag" taget="_blank" href="/search/autocomplete/1.htm">autocomplete</a><a class="tag" taget="_blank" href="/search/form/1.htm">form</a><a class="tag" taget="_blank" href="/search/%E6%B5%8F%E8%A7%88/1.htm">浏览</a>
                                    <div>  
                                   &n</div>
                                </li>
                                <li><a href="/article/577.htm"
                                       title="java的树形通讯录" target="_blank">java的树形通讯录</a>
                                    <span class="text-muted">g21121</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>最近用到企业通讯录,虽然以前也开发过,但是用的是jsf,拼成的树形,及其笨重和难维护。后来就想到直接生成json格式字符串,页面上也好展现。 
	// 首先取出每个部门的联系人
			for (int i = 0; i < depList.size(); i++) {
				List<Contacts> list = getContactList(depList.get(i</div>
                                </li>
                                <li><a href="/article/704.htm"
                                       title="Nginx安装部署" target="_blank">Nginx安装部署</a>
                                    <span class="text-muted">510888780</span>
<a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a>
                                    <div>Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源</div>
                                </li>
                                <li><a href="/article/831.htm"
                                       title="java servelet异步处理请求" target="_blank">java servelet异步处理请求</a>
                                    <span class="text-muted">墙头上一根草</span>
<a class="tag" taget="_blank" href="/search/%EF%BD%8A%EF%BD%81%EF%BD%96%EF%BD%81/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%82%E6%AD%A5%E8%BF%94%E5%9B%9E/1.htm">异步返回</a><a class="tag" taget="_blank" href="/search/%EF%BD%93%EF%BD%85%EF%BD%92%EF%BD%96%EF%BD%8C%EF%BD%85%EF%BD%94/1.htm">servlet</a>
                                    <div>servlet3.0以后支持异步处理请求,具体是使用AsyncContext ,包装httpservletRequest以及httpservletResponse具有异步的功能, 
   
  
  final AsyncContext ac = request.startAsync(request, response); 
  ac.s</div>
                                </li>
                                <li><a href="/article/958.htm"
                                       title="我的spring学习笔记8-Spring中Bean的实例化" target="_blank">我的spring学习笔记8-Spring中Bean的实例化</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/Spring+3/1.htm">Spring 3</a>
                                    <div>在Spring中要实例化一个Bean有几种方法: 
 
1、最常用的(普通方法) 
 
 
<bean id="myBean" class="www.6e6.org.MyBean" /> 
 
使用这样方法,按Spring就会使用Bean的默认构造方法,也就是把没有参数的构造方法来建立Bean实例。 
 
(有构造方法的下个文细说) 
 
2、还</div>
                                </li>
                                <li><a href="/article/1085.htm"
                                       title="为Mysql创建最优的索引" target="_blank">为Mysql创建最优的索引</a>
                                    <span class="text-muted">annan211</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E7%B4%A2%E5%BC%95/1.htm">索引</a>
                                    <div>


	索引对于良好的性能非常关键,尤其是当数据规模越来越大的时候,索引的对性能的影响越发重要。
	索引经常会被误解甚至忽略,而且经常被糟糕的设计。
	索引优化应该是对查询性能优化最有效的手段了,索引能够轻易将查询性能提高几个数量级,最优的索引会比
	较好的索引性能要好2个数量级。
	
	1 索引的类型
	  (1) B-Tree
	    不出意外,这里提到的索引都是指 B-</div>
                                </li>
                                <li><a href="/article/1212.htm"
                                       title="日期函数" target="_blank">日期函数</a>
                                    <span class="text-muted">百合不是茶</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/%E6%97%A5%E6%9C%9F%E5%87%BD%E6%95%B0/1.htm">日期函数</a><a class="tag" taget="_blank" href="/search/%E6%9F%A5%E8%AF%A2/1.htm">查询</a>
                                    <div>  
ORACLE日期时间函数大全

   TO_DATE格式(以时间:2007-11-02   13:45:25为例)
   
        Year:      
        yy two digits 两位年                显示值:07
        yyy three digits 三位年                显示值:007
   </div>
                                </li>
                                <li><a href="/article/1339.htm"
                                       title="线程优先级" target="_blank">线程优先级</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/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/java%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">java多线程</a>
                                    <div>多线程运行时需要定义线程运行的先后顺序。 
线程优先级是用数字表示,数字越大线程优先级越高,取值在1到10,默认优先级为5。 
实例: 
package com.bijian.study;

/**
 * 因为在代码段当中把线程B的优先级设置高于线程A,所以运行结果先执行线程B的run()方法后再执行线程A的run()方法
 * 但在实际中,JAVA的优先级不准,强烈不建议用此方法来控制执</div>
                                </li>
                                <li><a href="/article/1466.htm"
                                       title="适配器模式和代理模式的区别" target="_blank">适配器模式和代理模式的区别</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/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a>
                                    <div>一.简介        适配器模式:适配器模式(英语:adapter pattern)有时候也称包装样式或者包装。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类别自己的接口包裹在一个已存在的类中。      &nbs</div>
                                </li>
                                <li><a href="/article/1593.htm"
                                       title="【持久化框架MyBatis3三】MyBatis3 SQL映射配置文件" target="_blank">【持久化框架MyBatis3三】MyBatis3 SQL映射配置文件</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/Mybatis3/1.htm">Mybatis3</a>
                                    <div> SQL映射配置文件一方面类似于Hibernate的映射配置文件,通过定义实体与关系表的列之间的对应关系。另一方面使用<select>,<insert>,<delete>,<update>元素定义增删改查的SQL语句, 
这些元素包含三方面内容 
1. 要执行的SQL语句 
2. SQL语句的入参,比如查询条件 
3. SQL语句的返回结果</div>
                                </li>
                                <li><a href="/article/1720.htm"
                                       title="oracle大数据表复制备份个人经验" target="_blank">oracle大数据表复制备份个人经验</a>
                                    <span class="text-muted">bitcarter</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E8%A1%A8%E5%A4%87%E4%BB%BD/1.htm">大表备份</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E8%A1%A8%E6%95%B0%E6%8D%AE%E5%A4%8D%E5%88%B6/1.htm">大表数据复制</a>
                                    <div>前提: 
   数据库仓库A(就拿oracle11g为例)中有两个用户user1和user2,现在有user1中有表ldm_table1,且表ldm_table1有数据5千万以上,ldm_table1中的数据是从其他库B(数据源)中抽取过来的,前期业务理解不够或者需求有变,数据有变动需要重新从B中抽取数据到A库表ldm_table1中。 
    </div>
                                </li>
                                <li><a href="/article/1847.htm"
                                       title="HTTP加速器varnish安装小记" target="_blank">HTTP加速器varnish安装小记</a>
                                    <span class="text-muted">ronin47</span>
<a class="tag" taget="_blank" href="/search/http+varnish+%E5%8A%A0%E9%80%9F/1.htm">http varnish 加速</a>
                                    <div>上午共享的那个varnish安装手册,个人看了下,有点不知所云,好吧~看来还是先安装玩玩! 
苦逼公司服务器没法连外网,不能用什么wget或yum命令直接下载安装,每每看到别人博客贴出的在线安装代码时,总有一股羡慕嫉妒“恨”冒了出来。。。好吧,既然没法上外网,那只能麻烦点通过下载源码来编译安装了! 
Varnish 3.0.4下载地址: http://repo.varnish-cache.org/</div>
                                </li>
                                <li><a href="/article/1974.htm"
                                       title="java-73-输入一个字符串,输出该字符串中对称的子字符串的最大长度" target="_blank">java-73-输入一个字符串,输出该字符串中对称的子字符串的最大长度</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>

public class LongestSymmtricalLength {

	/*
	 * Q75题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。
	 * 比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。
	 */
	
	public static void main(String[] args) {
		Str</div>
                                </li>
                                <li><a href="/article/2101.htm"
                                       title="学习编程的一点感想" target="_blank">学习编程的一点感想</a>
                                    <span class="text-muted">Cb123456</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/%E6%84%9F%E6%83%B3/1.htm">感想</a><a class="tag" taget="_blank" href="/search/Gis/1.htm">Gis</a>
                                    <div>       写点感想,总结一些,也顺便激励一些自己.现在就是复习阶段,也做做项目. 
  
   本专业是GIS专业,当初觉得本专业太水,靠这个会活不下去的,所以就报了培训班。学习的时候,进入状态很慢,而且当初进去的时候,已经上到Java高级阶段了,所以.....,呵呵,之后有点感觉了,不过,还是不好好写代码,还眼高手低的,有</div>
                                </li>
                                <li><a href="/article/2228.htm"
                                       title="[能源与安全]美国与中国" target="_blank">[能源与安全]美国与中国</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E8%83%BD%E6%BA%90/1.htm">能源</a>
                                    <div> 
 
     现在有一个局面:地球上的石油只剩下N桶,这些油只够让中国和美国这两个国家中的一个顺利过渡到宇宙时代,但是如果这两个国家为争夺这些石油而发生战争,其结果是两个国家都无法平稳过渡到宇宙时代。。。。而且在战争中,剩下的石油也会被快速消耗在战争中,结果是两败俱伤。。。 
 
 
      在这个大</div>
                                </li>
                                <li><a href="/article/2355.htm"
                                       title="SEMI-JOIN执行计划突然变成HASH JOIN了 的原因分析" target="_blank">SEMI-JOIN执行计划突然变成HASH JOIN了 的原因分析</a>
                                    <span class="text-muted">cwqcwqmax9</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a>
                                    <div>甲说: 
A B两个表总数据量都很大,在百万以上。 
idx1  idx2字段表示是索引字段 
A B 两表上都有 
col1字段表示普通字段 
 
select xxx from A 
where A.idx1 between mmm and nnn 
     and exists (select 1 from B where B.idx2 =</div>
                                </li>
                                <li><a href="/article/2482.htm"
                                       title="SpringMVC-ajax返回值乱码解决方案" target="_blank">SpringMVC-ajax返回值乱码解决方案</a>
                                    <span class="text-muted">dashuaifu</span>
<a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/springMVC/1.htm">springMVC</a><a class="tag" taget="_blank" href="/search/response/1.htm">response</a><a class="tag" taget="_blank" href="/search/%E4%B8%AD%E6%96%87%E4%B9%B1%E7%A0%81/1.htm">中文乱码</a>
                                    <div>  
SpringMVC-ajax返回值乱码解决方案 
  
一:(自己总结,测试过可行) 
ajax返回如果含有中文汉字,则使用:(如下例:) 
@RequestMapping(value="/xxx.do")       public @ResponseBody void getPunishReasonB</div>
                                </li>
                                <li><a href="/article/2609.htm"
                                       title="Linux系统中查看日志的常用命令" target="_blank">Linux系统中查看日志的常用命令</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/OS/1.htm">OS</a>
                                    <div>因为在日常的工作中,出问题的时候查看日志是每个管理员的习惯,作为初学者,为了以后的需要,我今天将下面这些查看命令共享给各位 
cat 
tail -f 
日 志 文 件 说 明 
/var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一 
/var/log/secure 与安全相关的日志信息 
/var/log/maillog 与邮件相关的日志信</div>
                                </li>
                                <li><a href="/article/2736.htm"
                                       title="[应用结构]应用" target="_blank">[应用结构]应用</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/yii2/1.htm">yii2</a>
                                    <div>应用主体 
应用主体是管理 Yii 应用系统整体结构和生命周期的对象。 每个Yii应用系统只能包含一个应用主体,应用主体在 入口脚本中创建并能通过表达式 \Yii::$app 全局范围内访问。 
 
 补充: 当我们说"一个应用",它可能是一个应用主体对象,也可能是一个应用系统,是根据上下文来决定[译:中文为避免歧义,Application翻译为应</div>
                                </li>
                                <li><a href="/article/2863.htm"
                                       title="assertThat用法" target="_blank">assertThat用法</a>
                                    <span class="text-muted">eksliang</span>
<a class="tag" taget="_blank" href="/search/JUnit/1.htm">JUnit</a><a class="tag" taget="_blank" href="/search/assertThat/1.htm">assertThat</a>
                                    <div>junit4.0  assertThat用法 
一般匹配符1、assertThat( testedNumber, allOf( greaterThan(8), lessThan(16) ) ); 
注释: allOf匹配符表明如果接下来的所有条件必须都成立测试才通过,相当于“与”(&&) 
2、assertThat( testedNumber, anyOf( g</div>
                                </li>
                                <li><a href="/article/2990.htm"
                                       title="android点滴2" target="_blank">android点滴2</a>
                                    <span class="text-muted">gundumw100</span>
<a class="tag" taget="_blank" href="/search/%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">应用服务器</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8/1.htm">网络应用</a><a class="tag" taget="_blank" href="/search/OS/1.htm">OS</a><a class="tag" taget="_blank" href="/search/HTC/1.htm">HTC</a>
                                    <div>如何让Drawable绕着中心旋转? 
 

Animation a = new RotateAnimation(0.0f, 360.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);
a.setRepeatCount(-1);
a.setDuration(1000);
 
 
如何控制Andro</div>
                                </li>
                                <li><a href="/article/3117.htm"
                                       title="超简洁的CSS下拉菜单" target="_blank">超简洁的CSS下拉菜单</a>
                                    <span class="text-muted">ini</span>
<a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a>
                                    <div>效果体验:http://hovertree.com/texiao/css/3.htmHTML文件: 
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>简洁的HTML+CSS下拉菜单-HoverTree</title></div>
                                </li>
                                <li><a href="/article/3244.htm"
                                       title="kafka consumer防止数据丢失" target="_blank">kafka consumer防止数据丢失</a>
                                    <span class="text-muted">kane_xie</span>
<a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a><a class="tag" taget="_blank" href="/search/offset+commit/1.htm">offset commit</a>
                                    <div>kafka最初是被LinkedIn设计用来处理log的分布式消息系统,因此它的着眼点不在数据的安全性(log偶尔丢几条无所谓),换句话说kafka并不能完全保证数据不丢失。 
  
尽管kafka官网声称能够保证at-least-once,但如果consumer进程数小于partition_num,这个结论不一定成立。 
  
考虑这样一个case,partiton_num=2</div>
                                </li>
                                <li><a href="/article/3371.htm"
                                       title="@Repository、@Service、@Controller 和 @Component" target="_blank">@Repository、@Service、@Controller 和 @Component</a>
                                    <span class="text-muted">mhtbbx</span>
<a class="tag" taget="_blank" href="/search/DAO/1.htm">DAO</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/bean/1.htm">bean</a><a class="tag" taget="_blank" href="/search/prototype/1.htm">prototype</a>
                                    <div>@Repository、@Service、@Controller 和 @Component 将类标识为Bean 
Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的开发。@Repository注解便属于最先引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO类上即可。同时,为了让 Spring 能够扫描类</div>
                                </li>
                                <li><a href="/article/3498.htm"
                                       title="java 多线程高并发读写控制 误区" target="_blank">java 多线程高并发读写控制 误区</a>
                                    <span class="text-muted">qifeifei</span>
<a class="tag" taget="_blank" href="/search/java+thread/1.htm">java thread</a>
                                    <div>先看一下下面的错误代码,对写加了synchronized控制,保证了写的安全,但是问题在哪里呢? 
public class testTh7 {
	private String data;
	public String read(){
		System.out.println(Thread.currentThread().getName() + "read data " </div>
                                </li>
                                <li><a href="/article/3625.htm"
                                       title="mongodb replica set(副本集)设置步骤" target="_blank">mongodb replica set(副本集)设置步骤</a>
                                    <span class="text-muted">tcrct</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a>
                                    <div>网上已经有一大堆的设置步骤的了,根据我遇到的问题,整理一下,如下: 
 
首先先去下载一个mongodb最新版,目前最新版应该是2.6 
 

cd /usr/local/bin
wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.0.tgz
tar -zxvf  mongodb-linux-x86_64-2.6.0.t</div>
                                </li>
                                <li><a href="/article/3752.htm"
                                       title="rust学习笔记" target="_blank">rust学习笔记</a>
                                    <span class="text-muted">wudixiaotie</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">学习笔记</a>
                                    <div>1.rust里绑定变量是let,默认绑定了的变量是不可更改的,所以如果想让变量可变就要加上mut。 
let x = 1; let mut y = 2; 
2.match 相当于erlang中的case,但是case的每一项后都是分号,但是rust的match却是逗号。 
3.match 的每一项最后都要加逗号,但是最后一项不加也不会报错,所有结尾加逗号的用法都是类似。 
4.每个语句结尾都要加分</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>