zoukankan      html  css  js  c++  java
  • JS异步与同步

    这里展示一个操作场景:需要对数据进行异步处理,但这次操作可能会失败,所以需要定期对数据进行再次处理,直至处理成功。

    实现:手动触发的处理以及定期触发的处理,是相同的,即可以抽取出来成一个公共函数,定期操作使用setInterval实现,对应以下的示例代码:

    function otherAsyncApiCall(n){
        return new Promise(resolve => setTimeout(resolve, n * 1000))
    }
    
    // 抽取出公共的数据操作函数
    async function dataOperation(data){
        console.log(data + "读取数据库,并操作");
        // 模拟数据处理中的异步操作
        await otherAsyncApiCall(3);
        console.log(data + "操作结果写入数据库");
    }
    
    async function run(){
        // 开启定期操作,每5秒操作一次
        setInterval(()=>{
            dataOperation("定期触发 -");
        },5000);
    
        await dataOperation("1手动触发 -");
        await dataOperation("2手动触发 -");
    }
    run();

    执行结果:

    1手动触发 -读取数据库,并操作
    1手动触发 -操作结果写入数据库
    2手动触发 -读取数据库,并操作
    定期触发 -读取数据库,并操作
    2手动触发 -操作结果写入数据库
    定期触发 -操作结果写入数据库

    红色标记中出现一个严重问题:出现重复操作和写数据库。

    解决办法是换一种实现思路:

    维护一个全局的消息队列,添加一个额外的定时操作去定期消费队列中的消息,原有的定时操作以及手动触发都换成往队列中写数据,而不实际操作数据。这样一来,实际消费消息的地方只有一个,就能避免以上问题了。

    简易版的消息队列实现:

    +function(){
        const queue = [];
        const handlerMap = {};
        const gap = 5 * 1000;
    
        window.messageQueue = {
            put(type, data){
                queue.push({type, data})
            },
            get(){
                return queue.shift();
            },
    
            // 要求传入的fn必须返回一个Promise,告知执行的完成情况
            handle(type, fn){
                handlerMap[type] = fn;
            }
        };
        window.messageQueue.MSG_TYPE = {
            UPLOAD_IMG: 1,
        };
    
        async function eatMsg(){
            const target = queue.shift();
            if(!target){
                return;
            }
            const handlerFn = handlerMap[target.type];
            return handlerFn && handlerFn(target.data);
        }
    
        function range(){
            const next = ()=> setTimeout(range, gap);
    
            // 保证循环不会断
            eatMsg().then(next).catch(next);
        }
    
        range();
    }();

    ps:setInterval的循环中,不会受到await的影响而延迟,如以下代码中数据操作还没处理完,就会马上开始下一次触发,所以需要保证两次触发的时间间隔要大于实际的数据处理时间,才是安全的。

        setInterval(async ()=>{
            // 这里的异步操作是三秒
            await dataOperation("定期触发 -");
        },1000);
  • 相关阅读:
    windows10上安装 .NET Framework 3.5
    Mac上安装Tomcat服务器
    实验室中搭建Spark集群和PyCUDA开发环境
    训练实录
    Hello World
    存储管理
    java脚本实现selenium架构下的复选框、上传文件的操作
    java脚本,selenium工具,自动发QQ邮件
    用java脚本,selenium2.0工具,切换窗口经验总结
    六、排队论模型
  • 原文地址:https://www.cnblogs.com/hellohello/p/11857437.html
Copyright © 2011-2022 走看看