js 利用数组队列模拟多线程操作

不知道下面的想法对不对,如有错误还请大佬斧正

需求分析

有一批设备,数量很多,需要为他们开启远程驱动(即调用后台的远程驱动接口),问题是后台处理远程驱动只能一台一台设备处理,如果设备数量很多,后台php 在30s 内处理不完就会 timeout

  • 最开始的办法,将所以设备统统交给后台,接口只请求一次,这样做的结果是,这个请求常常超时(不可用)
    因为后台无法一次处理这么多数据,所以请求超时

  • 第二种想法:将所有设备分组,比如 3个一组,然后循环分组好的列表数组,在循环内部用闭包进行访问请求
    这样做的结果是会有很多个ajax请求在同时进行,也无法得到所有请求结束的时刻的钩子

  • 第三种想法(我们老大的想法):模拟线程操作,模拟同时开启多个线程,所有请求即设备列表放在一个线程池内(数组),每个线程的工作,只有当本次工作完成后,才可以继续去线程池内去拿新任务(即发送新情求),这样就可以控制同时请求的个数(线程数)以及请求结束的时刻的钩子。

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <!-- 一个驱动结果(每个线程的请求)实时显示的面板 -->
    <div id="drivepanel"></div>
</body>
<script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
<script>
    
    /*
    *  参数列表: 驱动设备的列表数组,驱动时长    
    */

    var drivelist = [1,2,3,4,5,6,7,8,9,10];         // 待驱动的设备列表
    var drivetime = 5;                                // 驱动时长

    var dom = $("#drivepanel");
    // 获得底层函数 return 出的对象
    var runui = rundeviceui();
    //向底层函数传入需要显示的面板
    runui.init(dom);

    //启动函数
    runui.start(drivelist,drivetime,function(){
        //程序运行中
        console.log('程序运行中!');
    },function(){
        //程序运行结束
        console.log("程序运行结束!");
    })

    //驱动设备的底层函数
    function rundeviceui() {
        return {
            init:function(context){
                this.context = context;
                this.r_init();
                this.c_init();
            },
            list:[],          // 列表数组,线程池(列表中的每一项相当于一个任务)
            drivetime:0,      //驱动时长
            onrun:null,          //运行时函数
            onend:null,          //运行结束时函数
            runnumber:3,      //同时开启的线程数量
            c_init:function(){      
                 //初始化一些操作
            },
            r_init:function(){
                //绑定事件操作
            },
            start:function(list,drivetime,onrun,onend){   //启动函数
                var me = this;
                this.list = list;
                this.drivetime = drivetime;
                this.onrun = onrun;
                this.onend = onend;

                //开启面板显示
                this.context.show();

                this.run(me.runnumber,function(){
                    me.onend();
                })
            },
            run:function(number,onend){    //运行时函数
                var me = this;
                var runnow = 0;            //正在运行的线程数
                for(var i=0; i<number; i++){
                    runnow++;
                    setTimeout(_run);           //依次开启事先设定好的线程(runnumber)
                }

        
                function _run(){
                    var data = me.list.shift();  //从线程池取出的任务
                    if(!data){                  //假如线程池内没任务了,调用结束函数
                        _runend() 
                    }else{
                        console.log('run',data);
                        var selfFun = arguments.callee;    //当前函数
                        me.showStatus(data,'已提交处理!');

                        // 程序运行中的钩子
                        me.onrun && me.onrun();

                        //调用请求接口
                        me.ajaxFn(data,drivetime,function(){
                            var status = "处理成功!";
                            me.showStatus(data,status);
                            setTimeout(selfFun);       //再次调用自身
                        })

                    }
                }

                // 结束函数
                // 当线程池内的任务处理完毕后,执行,_runend 函数,然后线程线程递减,当正在运行的线程数为 0 时调用任务完成函数
                function _runend(){
                    runnow--; 
                    if(runnow <= 0){     
                        onend && onend();
                    }
                }
            },

            showStatus:function(devicecode,status){    //面板显示请求的实时状态
                var me = this;
                //创建列表dom 元素,用 devicecode 当做 name 值
                var dom = this.context.find("[name="+ devicecode +"]");
                if(dom.length <= 0){ 
                    //假如该 dom 元素不存在,则创建
                    dom = this.c_getrow(devicecode,status);
                }

                //如果该 dom 元素已存在,则为其附上 合适的 status 值
                dom.html(devicecode + ":" + status);
            },

            c_getrow:function(devicecode,status){           //创建dom元素
                var me = this;
                var dom = $("<div></div>").attr('name',devicecode);
                this.context.append(dom);
                return dom;
            },

            //模拟后台的请求接口  
            ajaxFn:function(data,time,fn,fnerr){
                // 哒哒哒,,,发送ajax请求,请求失败暂不考虑

                setTimeout(function(){
                    fn && fn();
                },3000);
            }
        }
    }

</script>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值