微信小程序转换器(四)—— 异步loader实现

446 阅读1分钟

磨磨唧唧思考异步loader的拓展方式,最后从洋葱模型那里弄来了点灵感。表象上只用一点微小的修改,就可以使用异步的loader来修改源代码。

微信小程序转换器(一):转换器的实现。

微信小程序转换器(二):递归操作文件。

微信小程序转换器(三):loader设计实现。

微信小程序转换器(四):异步loader实现。

loader递归调用修改

判断loader返回值是否为promise,是就等待promise完成,得到值,否则直接获取返回值。

async function useLoader(source, loaders = []) {
	//...省略loader过滤阶段,假设loaderList = loaders
    
    const loaderList = loaders

    async function runLoader(source, loaderList) {
        const loader = loaderList.pop()
        let newSource
        if (isPromise(loader)) newSource = await loader(source)
        else newSource = loader(source)
        if (loaderList.length > 0) return runLoader(newSource, loaderList)
        else return newSource

    }

    source = await runLoader(source, loaderList)

    return source
}

获取loader处理结果

使用await等待异步loader返回结果。这里有个问题,假如使用Array.prototype上的foreach方法,是一个同步方法,无法提供一个可由外部控制的异步环境,将传入的callback进行堵塞,因此此处采用了for-of进行循环。

async function analyzeFileToLoard(inputPath, outputPath) {
    let source = readFile(inputPath)
    const loaders = config.module
    for (let loader of loaders) {
        if (loader.test.test(inputPath)) {
            source = await useLoader(source, loader.loader, outputPath)
            if (loader.outputPath) outputPath = loader.outputPath(outputPath)
        }
    }

    writeFile(outputAppPath(outputPath), source)
}

改进异步asyncForeach方法

可以用之前foreach的习惯调用。

Array.prototype.asyncForeach = async function(callBack) {
    if (callBack.constructor.name !== 'AsyncFunction') throw new Error('callBack should be AsyncFunction!')
    for (let i = 0; i<this.length; i ++ ) {
        const item = this[i]
        await callBack(item, i)
    }
}

// 调用
async function analyzeFileToLoard(inputPath, outputPath) {
    let source = readFile(inputPath)
    const loaders = config.module

    await loaders.asyncForeach(async loader => {
        if (loader.test.test(inputPath)) {
            const res = await useLoader(source, loader.loader, outputPath)
            source = res
            if (loader.outputPath) outputPath = loader.outputPath(outputPath)
        }
    })
    writeFile(outputAppPath(outputPath), source)
}