js消除异步的传染性

问题背景

现在看一道题目。是某厂的一个晋升题。异步传染性就是 当某一个函数节点是异步的时候 那他接下来的所有函数的调用都必须是异步

现在需要有什么办法可以消除函数中的副作用,使其变成同步的函数式编程。有人会讲,把async await 去掉不就好了吗,当然不可以因为 请求数据本身的操作是异步的

去掉 就返回了Promise 而不是我们想要的结果。返回的就会是一个Promise 我们希望能正常的接收结果

解决思路

函数开始=====>Fetch =====> 引发错误 =====> 函数结束 ======>缓存=====>函数继续

1. 首先必须在请求第一个函数做处理,首先请求是多次的 所以我们必须用数组来接受请求获得的参数,在他有缓存的时候 停止循环三次循环 直接返回缓存中的数据

JavaScript
function getList() {
            // 此处发送一个异步请求
            return fetch('/list.json')
        }
        function task1() {
            return getList()
        }
        function task2() {
            return task1()
        }
        function task3() {
            return task2()
        }
        /* 我们先写一个main函数  */
        function main() {
            const task3Run = task3()
            console.log(task3Run)
        }
        function run(fn) {
            /* 判断是否为promise函数 */
            const cache = []
            let i = 0
            const _originalFetch = window.fetch
            window.fetch = (...args) => {
                /* 发送请求,且报错 */
                /* 判断缓存如果存在,则交付缓存 */
                if (cache[i]) {
                    if (cache[i].status == 'fulfillled') {
                        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(res => res.json())
                    .then((resolve)=> {
                        result.status = 'fulfillled'
                        result.data = resolve
                    }, (inject) => {
                        result.status = 'rejected'
                        result.err = inject
                    })
                // 报错
                throw prom
            }
            try {
                fn()
            } catch (err) {
                if (err instanceof Promise) {
                    const reRun = () => {
                        i = 0;
                        fn()
                    }
                    err.then(reRun, reRun)
                }
            }
        }
        run(main)

当手动定义了缓存的格式,那就可以自己判定缓存的类型 来决定报错 还是正常返回数据

  1. 当成功的时候 返回正常的data
  2. 当失败的时候 抛出错误 注意 不是retun 否则后续的try catch接收不到

接下来就是手动报错 让函数停止 并且使用try catch捕获错误 来进行第二次返回缓存的函数请求

  1. 手动报错可以把请求的promise 抛出
  2. 在error中判定是否属于promise 而进行重复第二次请求

判断error是否是promise 而进行第二次请求 同时将下标清0

实际用到的地方

JSX
 const useResource = getUserResource()
 function profilePage(){
    return <Suspense fallback={<div>Loading...</div>}   >
        <ProfileDetails />
        <ProfilePosts />
    </Suspense>
 }

function ProfileDetails(){
    const user = useResource(userId)
    return <h1>{user.name}</h1>
}

function ProfilePosts(){
    const posts = useResource(userId, 'posts')
    return <ul>{posts.map(post => (
        <li key={post.id}>{post.text}</li>
    ))}</ul>
}

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<ProfilePage />)

vue 一般会要求中间组件返回promise

但在react中suspance组件是将中间组件是同步的

他会等到中间组件抛出异常再次执行中间的函数。类似于前面实现的效果


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注