用Generator函数和Promise对asyncawait进行模拟与转换

39次阅读

共计 2240 个字符,预计需要花费 6 分钟才能阅读完成。

Talk is cheap,show you the code

// 异步函数 1
function doLazy1() {return new Promise((rs, rj) => {setTimeout(() => {console.log('do Lazy1');
            rs();}, 1000)
    })
}
// 异步函数 2
function doLazy2() {return new Promise((rs, rj) => {setTimeout(() => {console.log('do Lazy2');
            rs();}, 2000)
    })
}
// 同步函数
function doNow() {console.log('do now!');
    return 'now'
}

 async function doAsync() {console.log('start');
    await doLazy1();
    console.log('after Lazy1');
    await doLazy2();
    console.log('after Lazy2');
    const res = await doNow();
    console.log('after now');
    return res;
}
doAsync();

// 打印出:
// start
// do Lazy1
// after Lazy1
// do Lazy2
// after Lazy2
// do now!
// after now
// 表达式输出为
// "now"

console.log('-----------------');

function runGenerator(generator) {const task = generator();
    let lastStep = task.next();

    function stepFoward() {if (lastStep.done === false) {return Promise.resolve(lastStep.value).then((res) => {lastStep = task.next(res);
                return stepFoward();})
        } else {console.log('done')
            return Promise.resolve(lastStep.value)
        }
    }
    return stepFoward();}    

//doAsync 被转换成:runGenerator(function* doAsyncFromGenerator() {console.log('start');
    yield doLazy1();
    console.log('after Lazy1');
    yield doLazy2();
    console.log('after Lazy2');
    const res = yield doNow();
    console.log('after now');
    return res;
})
// doAsync();
// 打印出:
// start
// do Lazy1
// after Lazy1
// do Lazy2
// after Lazy2
// do now!
// after now
// 表达式输出为
// "now"

//babel 插件思路
function transportAsyncFunction({types}) {
    return {
        visitor: {FunctionDeclaration(path) {if (path.node.async === true) {
                    path.node.async === false;
                    path.node.generator === true;
                }
                // 遍历函数内容
                path.traverse({AwaitExpression(pathAwait){
                    // 替换 AwaitExpression 节点为 YieldExpression
                    pathAwait.node.type = 'YieldExpression';
                }})
                // 把节点转换为 CallExpression
                // 创建 runGenerator 把节点转换为 CallExpression 并把上一步得到的节点当作 param
                // 替换上一步得到的节点
                types.replaceWith()}
        }
    }
}

//Function 构造函数思路
fucntion(target){
    // 匹配 async 关键字
    const regAsync = //s*async[^{}\(]{1,}(?=function|\()/;
    // 匹配 await 关键字
    const regAwait = /(?<=[/s]+)(await)(?=[/s]+)/g;
    const regBody = /(?<!{){(.*)}(?!})/;
    let funcStr = target.toString();
    let resultStr = null;
    resultStr = funcStr.replace(regAsync,'*');
    // 如果是箭头函数需要转换成普通函数
    resultStr = funcStr.replace(/\(([/w]+)\)[/s]*=>/,'function($0)');
    // 提取参数
    const params = funcStr.replace(/\(([/w]*)\)/,'$0').split(',');
    resultStr = funcStr.replace(regAwait,'yield');
    const body = resultStr.replace(regBody,'$1');
    // 构造出函数
    const resultFunction = new Function(...params,body);
    return runGenerator(resultFunction());
}

正文完
 0