第一步
实现一个手写的genator 函数
/**
* 第一步
* @description 实现一个手写的genator 函数
* */
// 测试的generator函数
function* test() {
var a = 1;
yield a;
let b = 2;
return a
}
// babel 对 generator code split(草鞋版)
function splitIterator(fx) {
let code = fx.toString().match(/{(.|\s)*}/g)[0].slice(1, -1);
// 从代码中提取变量,变量提升
let variable = code.match(/let(\s*).|var(\s*).|const(\s*).*/g).join(";");
// 移除主体代码中的变量声明
let rmCodeVeriable = code.replace(/let|var|const/g, '');
// 替换yield为return,按照yield切片
let mainCode = rmCodeVeriable.match(/(.|\s)*?(yield|return).*/g).map(v => v.replace(/yield/g, "return"))
// yield切片实际执行代码
const codeTranslate = mainCode.map((v, i) => {
return `
case ${i}:
context.next = ${i+1}
context.done = ${i+1 >= mainCode.length ? 'true' : 'false'}
${
v
// replace(/(.+\s*=*\s*)(yield|return)(\s*.*)/g,`$2$3$1p`)
}
`
})
// next方法实际执行函数
const excuteFx = `
var fx = function (){
while(1){
switch(context.per = context.next){
${codeTranslate.join("")}
default:
context.done = true
context.value = undefined
return;
}
}
}
`
return {
variable,
excuteFx
}
}
// console.log(splitIterator(test))
function Generator(test, fxString) {
// 转换Generator函数为ES3
const {
variable,
excuteFx
} = splitIterator(test)
// 上下文环境
const context = {
per: 0,
next: 0,
done: false,
value: undefined
}
// 进行变量提升
eval(variable)
// 声明next函数实际执行函数
eval(fxString || excuteFx)
// 迭代器
return {
next: function(paramters) {
return {
value: fx(paramters),
done: context.done,
}
}
}
}
var a = Generator(test)
console.log(a.next())
console.log(a.next())
console.log(a.next())
第二步
使用generator手写一个代替async&await函数可的函数
/**
* 第二步
* @description 使用generator手写一个代替async&await函数可的函数
* */
async function testTemple() {
var content = await fetch("https://juejin.cn/post/6844903929369591822");
console.log(await content.text())
return content
}
function executeAsyncFX(iterator) {
var gen = iterator || (function* asyncFxAsGenator() {
var content = yield fetch(
"http://127.0.0.1:8848/note/%E5%89%8D%E7%AB%AF/%E6%89%8B%E5%86%99/Generator.html");
console.log("2222")
console.log(yield content.text())
return content
})(); // 将async函数testTemple转化成一个 generator函数
(function(value) { //不能使用箭头函数,因为这样arguments.callee指向会执行上级
const results = gen.next(value);
// console.log(results)
Promise.resolve(results.value).then(
(v) => {
// console.log(v)
if (!results.done) {
console.log(v)
arguments.callee(v)
}
}
);
})() // 让这个iterator自执行知道完成,遇到返回promise 也就是 awaite后面的表达式保证执行完成,并将结果传入下一次执行
}
executeAsyncFX()
第三步
使用第一步中手写的generator 代替第二步中的 generator
/**
* 第三步
* @description 使用第一步中手写的generator 代替第二步中的 generator
* */
var gen = function* asyncFxAsGenator() {
var content = yield fetch("http://127.0.0.1:8848/note/%E5%89%8D%E7%AB%AF/%E6%89%8B%E5%86%99/Generator.html");
console.log("2222")
console.log(yield content.text())
return content
}
// 上面的代码分割函数转化不了,手动改了下
var iterator = Generator(gen, `var fx = function (paramters){
while(1){
switch(context.per = context.next){
case 0:
context.next = 1
context.done = false
return fetch("http://127.0.0.1:8848/note/%E5%89%8D%E7%AB%AF/%E6%89%8B%E5%86%99/Generator.html");
case 1:
content = paramters
context.next = 2
context.done = false
console.log("2222")
return content.text()
case 2:
context.next = 3
context.done = true
return content
default:
context.done = true
context.value = undefined
return;
}
}
}`)
executeAsyncFX(iterator)
总结:aync函数手写实现
- 可以通过一个自动执行的generator实现,实际内部也依靠Promise.resolve,then 回调函数递归实现。
- 也可以通过babel直接将await后面表达式转成Promise.resolve在then回调里面执行余下直到下一个await的代码,也就是回调地域。
- 也就是说async的实现实际上依赖的是promise。