Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Babel是如何编译async和generator的 #42

Open
sl1673495 opened this issue Mar 24, 2020 · 4 comments
Open

Babel是如何编译async和generator的 #42

sl1673495 opened this issue Mar 24, 2020 · 4 comments

Comments

@sl1673495
Copy link
Owner

mqyqingfeng/Blog#103

这个系列的两篇

@sl1673495
Copy link
Owner Author

generator函数其实就是维护了一个迭代对象,不停的给这个对象改变状态,直到最后的done。

@sl1673495
Copy link
Owner Author

而async函数的关键则是这个函数

function _asyncToGenerator(fn) {
  return function() {
    var gen = fn.apply(this, arguments);
    return new Promise(function(resolve, reject) {
      function step(key, arg) {
        try {
          var info = gen[key](arg);
          var value = info.value;
        } catch (error) {
          reject(error);
          return;
        }
        if (info.done) {
          resolve(value);
        } else {
          // 注意这里的value 很可能是一个promise
          // 而then方法是具有解开promise的功能的
          // 自然也可以异步等待这个promise被resolve以后
          // 再继续执行下一步
          return Promise.resolve(value).then(
            function(value) {
              step("next", value);
            },
            function(err) {
              step("throw", err);
            }
          );
        }
      }
      return step("next");
    });
  };
}

@sl1673495
Copy link
Owner Author

function* testG() {
  // await被编译成了yield
  const data = yield getData()
  console.log('data: ', data);
  const data2 = yield getData()
  console.log('data2: ', data2);
  return data + '123'
}

假设有这样一个函数,那么其实每次yield都会中止函数,并且外部可以拿到promise

我们就可以在这个promise的then里面,再去把迭代器进一步的调用.next()

这样就可以做到 只有在promise被resolve了以后 迭代器里才会继续前进到下一个yield

其实原理类似于一个generator的autorun,只是支持了promise异步

@sl1673495
Copy link
Owner Author

最终版本

/**
 * async的执行原理
 * 其实就是自动执行generator函数
 * 暂时不考虑genertor的编译步骤(更复杂)
 */

const getData = () =>
  new Promise(resolve => setTimeout(() => resolve("data"), 1000))

// 这样的一个async函数 应该再1秒后打印data
async function test() {
  const data = await getData()
  
  console.log(data)
  return data
}

// async函数会被编译成generator函数 (babel会编译成更本质的形态,这里我们直接用generator)
function* testG() {
  // await被编译成了yield
  const data = yield getData()
  console.log('data: ', data);
  const data2 = yield getData()
  console.log('data2: ', data2);
  return data + '123'
}

function asyncToGenerator(generatorFunc) {
  return function() {
    const gen = generatorFunc.apply(this, arguments)

    return new Promise((resolve, reject) => {
      function step(key, arg) {
        let generatorResult
        try {
          generatorResult = gen[key](arg)
        } catch (error) {
          return reject(error)
        }

        const { value, done } = generatorResult

        if (done) {
          return resolve(value)
        } else {
          return Promise.resolve(value).then(
            function onResolve(val) {
              step("next", val)
            },
            function onReject(err) {
              step("throw", err)
            },
          )
        }
      }
      step("next")
    })
  }
}

const testGAsync = asyncToGenerator(testG)
testGAsync().then(result => {
  console.log(result)
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant