消除异步传染性问题

335 阅读1分钟

解决异步传染问题,将异步转同步,可以使用下面的方法: image.png

修改前:

async function getUser() {
    return await fetch('https://example').then(resp => resp.json())
}

async function m1() {
    return await getUser()
}

async function m2() {
    return await m1()
}

async function m3() {
    return await m2()
}

async function main() {
    const user = await m3()

    console.log(user)
}

main()

修改后:

function getUser() {
    return fetch('https://example')
}

function m1() {
    return getUser()
}

function m2() {
    return m1()
}

function m3() {
    return m2()
}

function main() {
    const user = m3()

    console.log(user)
}

function run(func) {
    let cache = []
    let i = 0
    const _originalFetch = window.fetch

    // 先将fetch重新定义,另其可以交付缓存结果、发送请求 和 抛出异常
    window.fetch = (...args) => {
        if(cache[i]) {
            // 交付缓存结果
            if(cache[i].status === 'fulfilled') {
                return cache[i].data
            }else if (cache[i].status === 'rejected') {
                throw cache[i].err
            }
        }
        const result = {
            status: 'pending',
            data: null,
            err: null
        }
        cache[i++] = result
        // 发送请求
        const prom = _originalFetch(...args).then(resp => resp.json()).then(resp => {
            result.status = 'fulfilled'
            result.data = resp
        },err => {
            result.status = 'rejected'
            result.err = err
        })
        // 报错
        throw prom
    }
    try {
        // 执行函数,此时函数中的fetch方法已被重写
        func()
    } catch (err) {
        if(err instanceof Promise) {
            const reRun = () => {
                i = 0
                func()
            }

            err.then(reRun,reRun)
        }
    }
}

run(main)