await/async 是 ES7 最重要特性之一,相对于Ajax、Promise、Generators等,它是目前为止 JS 最佳的异步解决方案(回调函数、事件监听、发布/订阅、Promise对象)了。
插一句:这里我就只介绍下Generators,详细可以去看阮老师的Generators函数的含义与用法
强劲的Generators
小总结:调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
1 2 3 4 5 6 7 8 9 10 11 
  | //单纯的暂缓执行函数(不包含next方法) function* f() {   console.log('执行了!') } var generator = f(); setTimeout(function () {   generator.next() }, 2000); //输出结果为:2秒以后打印“执行了”。 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
  | //generator函数(包含next方法) function* helloWorldGenerator() {   yield 'hello';   yield 'world';   return 'ending'; } var hw = helloWorldGenerator(); //输出为: hw.next() // { value: 'hello', done: false } hw.next() // { value: 'world', done: false } hw.next() // { value: 'ending', done: true } hw.next() // { value: undefined, done: true } 
  | 
 
言归正传,下面来看下Async/Await方法
看个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
  | var sleep = function (time) {     return new Promise(function (resolve, reject) {         setTimeout(function () {             resolve();         }, time);     }) }; var start = async function () {     // 在这里使用起来就像同步代码那样直观     console.log('start');     await sleep(3000);     console.log('end'); }; start(); //输出结果:控制台先输出start,稍等3秒,输出end 
  | 
基本规则
async表示这是一个async函数,await只能用在这个函数里面。
 
await 表示在这里等待promise返回结果了,再继续执行。
 
await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)
 
返回值
await等待的虽然是promise对象,但不必写.then(..),直接可以得到返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
  | var sleep = function (time) {     return new Promise(function (resolve, reject) {         setTimeout(function () {             // 返回 ‘ok’             resolve('ok');         }, time);     }) }; var start = async function () {     let result = await sleep(3000);     console.log(result); }; // 3秒以后收到 ‘ok’ 
  | 
捕捉错误
直接用标准的    try catch语法捕捉错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
  | var sleep = function (time) {     return new Promise(function (resolve, reject) {         setTimeout(function () {             // 模拟出错了,返回 ‘error’             reject('error');         }, time);     }) }; var start = async function () {     try {         console.log('start');         await sleep(3000); // 这里得到了一个返回错误         // 所以以下代码不会被执行了         console.log('end');     } catch (err) {         console.log(err); // 这里捕捉到错误 `error`     } }; 
  | 
循环多个await
await看起来像同步代码,所以可以理所当然的写在for循环里,不必担心以往需要闭包才能解决的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
  | ..省略以上代码 let arr = [1,2,3,4,5,6,7,8,9,10]; // 错误示范 arr.forEach(function (v) {     console.log(`当前是第${v}次等待..`);     await sleep(1000); // 错误!! await只能在async函数中运行 }); // 正确示范 for(var v of arr) {     console.log(`当前是第${v}次等待..`);     await sleep(1000); // 正确, for循环的上下文还在async函数中 } 
  | 
结论:await只能在async函数的上下文中。
结合Fetch
1 2 3 4 5 6 7 8 
  | (async () => {     let parallelDataFetch = await* [         (await fetch('products.json')).json(),         (await fetch('users.json')).json(),         (await fetch('comments.json')).json()     ];     console.log('Async parallel+fetch >>>', parallelDataFetch); }()); 
  | 
 
promise与async比较
async本身就是基于Promise的语法糖。如果你懒得看语法细节,监测当前上下文能否支持async的代码里就能看出这一点:
1 2 3 4 5 
  | function(){ return (async function(){   return 42; })() instanceof Promise }   //返回true 
  | 
然而,很多Promise方法你不能用async来定义,而只能用Promise的方式来定义。Promise就是用于解决回调函数的了,而async的写法没办法在异步回调里插入resolve/reject…
1 2 3 4 5 6 
  | function returnPromise(){     return new Promise(function(resolve,reject){         setTimeout(function(){resolve(42)})     }) } //这个用async是不能改写的。 
  |