晴明的博客园 GitHub      CodePen      CodeWars     

[ES8] async

#

async函数就是Generator函数的语法糖。

 


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


async函数对 Generator 函数的改进:

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

(2)更好的语义。
async和await,比起星号和yield,语义更清楚了。
async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。
co模块约定,yield命令后面只能是Thunk函数或Promise对象,而async函数的await命令后面,
可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

(4)返回值是Promise。
async函数的返回值是Promise对象,
这比Generator函数的返回值是Iterator对象方便多了。
可以用then方法指定下一步的操作。

 


Async函数有多种使用形式。

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

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

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

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

 



#

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);
    });
  });
};

// generator
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());
};
var result = asyncReadFile();//执行

 

(1)async函数返回一个Promise对象。

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

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

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


#async函数内部抛出错误,会导致返回的Promise对象变为reject状态。
抛出的错误对象会被catch方法回调函数接收到。

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

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

 

(2)async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
#

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"

 

(3)正常情况下,await命令后面是一个Promise对象。
#如果不是,会被转成一个立即resolve的Promise对象。

async function f() {
  return await 123;
}

f().then(v => console.log(v))
// 123

#await命令后面的Promise对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。

async function f() {
  await Promise.reject('出错了');
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了


#只要一个await语句后面的Promise变为reject,那么整个async函数都会中断执行。

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}


#为了避免这个问题,可以将第一个await放在try...catch结构里面,这样第二个await就会执行。

async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

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


#另一种方法是await后面的Promise对象再跟一个catch方面,处理前面可能出现的错误。

async function f() {
  await Promise.reject('出错了')
    .catch(e => console.log(e));
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// 出错了
// hello world

 

#async 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。

async function fn(args){
  // ...
}

// 等同于

function fn(args){
  return spawn(function*() {
    // ...
  });
}

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    var gen = genF();
    function step(nextF) {
      try {
        var next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

 

#指定多少毫秒后输出一个值。

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

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

asyncPrint('hello world', 50);


#多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;


#多个请求并发执行

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);
}

// 或者使用下面的写法

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) {
    results.push(await promise);
  }
  console.log(results);
}


#await命令只能用在async函数之中,如果用在普通函数,就会报错。

//
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  // 报错
  docs.forEach(function (doc) {
    await db.post(doc);
  });
}

//
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  // 可能得到错误结果
  docs.forEach(async function (doc) {
    await db.post(doc);
  });
}

//
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await db.post(doc);
  }
}

 

与Promise、Generator的比较

假定某个DOM元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。
如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。

#Promise的写法。

function chainAnimationsPromise(elem, animations) {

  // 变量ret用来保存上一个动画的返回值
  var ret = null;

  // 新建一个空的Promise
  var p = Promise.resolve();

  // 使用then方法,添加所有动画
  for(var anim in animations) {
    p = p.then(function(val) {
      ret = val;
      return anim(elem);
    });
  }

  // 返回一个部署了错误捕捉机制的Promise
  return p.catch(function(e) {
    /* 忽略错误,继续执行 */
  }).then(function() {
    return ret;
  });

}

 

#Generator函数的写法。

spawn函数是自动执行器

function chainAnimationsGenerator(elem, animations) {

  return spawn(function*() {
    var ret = null;
    try {
      for(var anim of animations) {
        ret = yield anim(elem);
      }
    } catch(e) {
      /* 忽略错误,继续执行 */
    }
    return ret;
  });

}

 

#Async函数的写法。

async function chainAnimationsAsync(elem, animations) {
  var ret = null;
  try {
    for(var anim of animations) {
      ret = await anim(elem);
    }
  } catch(e) {
    /* 忽略错误,继续执行 */
  }
  return ret;
}

 

 #

import path  from 'path';
import fs from 'fs';

let a = path.join(__dirname, 'a');
let b = path.join(__dirname, 'b');
let c = path.join(__dirname, 'c');
let d = path.join(__dirname, 'd');
let e = path.join(__dirname, 'e');
//console.log(p)

//let aa = mkdir(a);
//let bb = mkdir(b);
//let cc = mkdir(c);
//let dd = mkdir(d);
//let ee = mkdir(e);
let content = [a, b, c, d, e];
let sequence = [];

async function xx() {
    console.log('in');
    //sequence = content.map((v) => mkdir(v));

    //for (let v of content) {
    //    let k = mkdir(v);
    //    sequence.push(k);
    //}
    //console.log(sequence);
    //await Promise.all(sequence);//异步
    for (let v of content) {
        await mkdir(v);//有序
    }
}
xx();
//for (let v of content) {
//    mkdir(v);//异步
//}

function mkdir(fp) {
    return new Promise((resolve, reject)=> {
        fs.mkdir(fp, (error)=> {
            if (error) {
                reject(error);
            } else {
                console.log(fp)
                resolve();
            }
        })
    });
}

 





 






 

posted @ 2016-06-08 12:00  晴明桑  阅读(350)  评论(0编辑  收藏  举报