async/await使用generator实现、generator底层实现

generator基本使用

function* gen() { 
  yield 1;
  yield 2;
  yield 3;
}

let g = gen();

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

await的阻塞效果通过.then的回调必须在调用执行器resolve之后才会执行,然后将generator自循环实现自动调用的功能放进.then的回调中,实现yield后的异步promise阻塞效果

阻塞简单示例:

Promise.resolve(
  new Promise((resolve) => {
    setTimeout(() => {
      resolve(2);
    }, 3000);
  })
).then((res) => {
  console.log("哇擦擦");
});

代码示例

//fn是一个generator
function _asyncToGenerator(fn) {
  return function() {
    var self = this,
      args = arguments;
    // 将返回值promise化
    return new Promise(function(resolve, reject) {
      // 获取迭代器实例
      var gen = fn.apply(self, args);
      // 执行下一步
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
      }
      // 抛出异常
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
      }
      // 第一次触发
      _next(undefined);
    });
  };
}

asyncGeneratorStep

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    // 迭代器完成,将返回值(return)保存起来
    resolve(value);
  } else {
	 //进行阻塞,并递归调用实现yield自动调用
    Promise.resolve(value).then(_next, _throw);
  }
}

执行结果和async/await阻塞效果一致

const asyncFunc = _asyncToGenerator(function* () {
  console.log(1);
  yield new Promise(resolve => {
    setTimeout(() => {
      resolve();
      console.log('sleep 1s');
    }, 1000);
  });
  console.log(2);
  const a = yield Promise.resolve('a');
  console.log(3);
  const b = yield Promise.resolve('b');
  const c = yield Promise.resolve('c');
  return [a, b, c];
})

asyncFunc().then(res => {
  console.log(res)
});

// 运行结果
// 1
// sleep 1s
// 2
// 3
// ["a", "b", "c"]

async/await执行结果

const func = async () => {
  console.log(1)
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve()
      console.log('sleep 1s')
    }, 1000)
  })
  console.log(2)
  const a = await Promise.resolve('a')
  console.log(3)
  const b = await Promise.resolve('b')
  const c = await Promise.resolve('c')
  return [a, b, c]
}

func().then(res => {
  console.log(res)
})

// 运行结果
// 1
// sleep 1s
// 2
// 3
// ["a", "b", "c"]

babel中generator转换后代码

  • 每一个yied分割的代码块都是一个switch的case,每一次执行会指向下一个case的值
  • regeneratorRuntime.wrap相当于是每一个yield的调用,会往_context上绑定下一个case的值
// 这是我们的异步生成器
var asyncFunc = _asyncToGenerator(
// regeneratorRuntime 这个对象是 迭代器的运行时,mark函数 将所有的变量保存在它作用域下
regeneratorRuntime.mark(function _callee() {
  var a, d, b, c;
  // wrap 是对下面代码片段的一个包裹函数,每执行一次迭代就会调用一次 _callee$
  // _context.next, 执行完本次迭代后将指针指到下一个迭代
  return regeneratorRuntime.wrap(function _callee$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          // --------- ⬇⬇ 这是第一个代码片段 ⬇⬇ -----------
          console.log(1);
          _context.next = 3;
          return new Promise(function (resolve) {
            setTimeout(function () {
              resolve();
              console.log('sleep 1s');
            }, 1000);
          });
          // --------- ⬆⬆ 这是第一个代码片段 ⬆⬆ -----------
        case 3:
          // --------- ⬇⬇ 这是第二个代码片段 ⬇⬇ -----------
          console.log(2);
          _context.next = 9;
          return Promise.resolve('a');
          // --------- ⬆⬆ 这是第二个代码片段 ⬆⬆ -----------
          // ...
          // ... 下面以此类推每一个 yield 会被放进一个 case,作为一个代码片段,
          // ... 每次执行完就return,并且将 _context.next 指向下一个
          // ... 等待下次调用
        case 9:
          d = _context.sent;
          console.log(3);
          _context.next = 13;
          return Promise.resolve('b');

        case 13:
          b = _context.sent;
          _context.next = 16;
          return Promise.resolve('c');

        case 16:
          c = _context.sent;
          return _context.abrupt("return", [a, b, c, d]);

        case 18:
        case "end":
          // 最后执行 stop 结束
          return _context.stop();
      }
    }
  }, _callee);
}));

asyncFunc().then(function (res) {
  console.log(res);
}); 

你可能感兴趣的:(功能库源码,javascript,前端,vue.js)