美文网首页
消除async/await异步的传染性

消除async/await异步的传染性

作者: 猪猪行天下 | 来源:发表于2023-11-04 16:44 被阅读0次

我们看下下面函数的调用:

async function getUser() {
    return await fetch('./1.json');
}

async function m1() {
    const user = await getUser();
    return user;
}

async function m2() {
    const user = await m1();
    return user;
}
async function m3() {
    const user = await m2();
    return user;
}

async function main() {
    const user = await m3();
    console.log(user);
}

从上面的函数调用可以看出来,getUser是异步函数,所有使用和相关联的函数都必须使用async/await变成异步函数,这样使用也没有什么问题,但是在函数式编程环境中就不合适了。
本来这些函数应该是一个纯函数的,却因为异步具有传染性,导致这些函数全部变成副作用的了,这在函数式编程环境中是很难接受的。

所以如何不去改动这些函数,把这些异步全部去掉呢?变成没有异步的样子,从而保持这些函数的纯度。如下:

 function getUser() {
    return fetch('./1.json');
}

 function m1() {
    const user = getUser();
    return user;
}

 function m2() {
    const user = m1();
    return user;
}
 function m3() {
    const user = m2();
    return user;
}

 function main() {
    const user = m3();
    console.log(user);
}

怎么操作呢?getUser调用了fetch请求,导致了异步的产生。
网络传输是需要时间的,这个是无法改变的。让浏览器完全阻塞那就卡死了,肯定是行不通的。
目前的函数调用流程如下:

fetch-1.png

main->getUser->fetch - -> 等待网络请求,请求完成 --> getUser->main

由于fetch需要等待导致所有相关的函数都要等待。那么只能在fetch这里做一些操作了。如何让fetch不等待,就只能报错了。

fetch-2.png

我们看下通过fetch报错如何解决这个问题。

main->getUser->fetch->error
拿到结果存入cache: main->getUser->fetch->cache->getUser->main

在调用fetch的时候不等待了而是报错,这样所有函数都终止了,调用栈层层弹出,调用结束。

但是我们最终的目的是要拿到结果的,前面虽然报错了,网络线程仍然还在继续网络请求它不会停止,直到拿到结果。

拿到结果后我们把它放在一个缓存中,接着再去恢复整个调用链的执行。再执行fetch时,结果已经缓存在cache了,取出数据就可以直接交付不用等待了从而变成了同步函数。

整个过程会走两次,第一次以错误结束,第二次以成功结束,这两次都是同步的。

在这个过程中fetch的逻辑就发生了变化:
fetch时要判断是否有缓存,如果有缓存则返回缓存,如果没有缓存则发送真实请求同时抛出错误,然后把请求的结果保存。抛出的错误为发送请求返回的Promise对象,目的是为了在请求完成后再去恢复调用。

伪代码实现如下:

function run(func) {
    let cache = {
        status: 'pending',
        value: null
    };
    const oldFetch = window.fetch;
    window.fetch = function(...args){
        if(cache.status == 'fulfilled'){
            return cache.value;
        }else if(cache.status == 'rejected'){
            //之前的请求有问题
            throw cache.value;
        }else{
            // 1. 发送真是请求
            const promise = oldFetch(...args)
            .then(res=>{
                cache.status = 'fulfilled';
                cache.value = res;
            }, err=> {
                cache.status = 'rejected';
                cache.value = err;
            });
            // 2. 抛出错误
            throw promise;
        }
        
    }
    // 执行入口函数
    try {
        func();
    } catch (error) {
        if(error instanceof Promise) {
            // 不论成功还是失败都重新调用
            error.then(func,func).finally(()=>{
                //恢复原来的值
                window.fetch = oldFetch;
            });
        }
    }
    
}
run(main);

在实际环境中cache需要保存每个请求,给每个请求设置一个key,通过key从缓存中获取每个请求返回的数据。

在react环境中是大量应用这种方式的。react内置组件Suspense,它的作用就是当它子组件出现异步的时候可以等待,并在fallback属性显示一个等待的提示或loading。Suspense内部会捕获promise错误,一旦捕获了就会等待promise完成,在等待期间就会渲染fallback内容,直到promise完成再重新去渲染,也就是会重新调用一次这个函数组件得到新的内容。

const App = ()=> {
    return (
        <div className="app" id='app'>
            <Suspense fallback={<p>Loading user ...</p>}>
                <User/>
            </Suspense>
        </div>
    )
}

User简单示例如下:

import {getData} from '../api/fetchData';

const resource = getData()

const User = () => {
    const userInfo = resource.read();
    return (
        <div>{userInfo.name}</div>
    )

}
export {
    User
}

相关文章

  • async和await

    浅谈Async/Await用 async/await 来处理异步 async和await async:声明一个异步...

  • async

    async/await特点 async/await更加语义化,async是“异步”的简写,async functi...

  • ES8(一) —— async&await

    目录 async和普通函数的区别 await async/await处理多回调异步 async和await必须配合...

  • 2018-04-03 async/await学习

    async/await async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法...

  • JS 中的 async/await

    async/await 是什么? async/await 是 ES2017 中新增的异步解决方案; await 只...

  • Async/Await VS Promise

    Async/Await VS Promise Async/await 是一种编写异步代码的新方法。之前异步代码的方...

  • 3.2KOA async/await 语法

    async/await 语法 作用 解决异步嵌套问题,传说中的终极解决方案 异步问题 async/await 实现...

  • es6--async和await

    async 和 await被称为js异步的最终解决方案,那么我们来了解下:async:异步方法, await:等待...

  • ES2017 async 函数

    async 和 await 在干什么 每个名称都有意义async : 异步await: async wait简...

  • async await 异步的简单用法

    async 是声明一个异步函数,如 async ()=>{} await 是等待一个异步方法执行,await 执行...

网友评论

      本文标题:消除async/await异步的传染性

      本文链接:https://www.haomeiwen.com/subject/ymvaidtx.html