异步函数(async/await)的原理

Generator

了解一个异步函数的原理,首先要来看下Generator(具体内容去看文档):

function* fibonacci() {
   try{
      var a = yield 1;
      yield a * 2;
    }catch(err){
      console.log(err.message);
    }
}

var it = fibonacci();      
it.next();   // {value: 1, done: false}
it.next(10); // {value: 20, done: false}
it.throw(new Error("saiban")); // saiban            

总结一下:
● yield允许一个generator函数暂停执行,并且将恢复执行的权力交给外部系统。
● 外部系统可以将值推入generator函数体。
● 外部系统可以将一个异常抛入generator函数体。

async/await

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

const fs = require('fs');

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

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

上面代码的函数gen可以写成async函数,就是下面这样。

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

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

  1. 内置执行器,不要手动调用next方法
  2. 更好的语义
  3. 更广的适用性
  4. 函数返回值是Promise对象

利用Generator实现async函数

实现的关键:就是完成一个内置执行器,再返回Promise对象。

const _awaiter = function(thisArg, _arguments, generator){
    return new Promise(function(resolve, reject){
        function fulfilled(value){
            try {
                step(generator.next(value));
            } catch (error) {
                reject(error);
            }
        }

        function rejected(value){
            try {
                step(generator.throw(value));
            } catch (error) {
                reject(error);
            }
        }

        //自带执行器
        function step(result){
            result.done //是否执行完成
            ? resolve(result.value) //是,fulfilled状态,返回终值
            : new Promise(function(resolve){ //否,返回Promise
                resolve(result.value);       //如果yield后是Promise,result.value就是Promise
            }).then(fulfilled,rejected);     //等待Promise执行完再继续执行
        }

        //开始执行
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

//异步函数返回一个Promise
const asyncReadFile = function () {
    return _awaiter(this,void 0, function* (){
        const f1 = yield readFile('/etc/fstab');
        const f2 = yield readFile('/etc/shells');
        console.log(f1.toString());
        console.log(f2.toString());
    });
};

从以上代码,我们可以得到一个信息,那就是readFile是fulfilled状态,asyncReadFile调用内部执行器,才会继续向下执行, 两次readFile只有都是fulfilled状态,它返回的Promise的执行结果才是fulfilled状态,否则就是rejected状态。

参考资料:

  1. ECMAScript 6 入门

你可能感兴趣的:(web前端,javascript)