js 利用數組隊列模擬多線程操做

不知道下面的想法對不對,若有錯誤還請大佬斧正

需求分析

有一批設備,數量不少,須要爲他們開啓遠程驅動(即調用後臺的遠程驅動接口),問題是後臺處理遠程驅動只能一臺一臺設備處理,若是設備數量不少,後臺php 在30s 內處理不完就會 timeoutphp

  • 最開始的辦法,將因此設備通通交給後臺,接口只請求一次,這樣作的結果是,這個請求經常超時(不可用)
    由於後臺沒法一次處理這麼多數據,因此請求超時html

  • 第二種想法:將全部設備分組,好比 3個一組,而後循環分組好的列表數組,在循環內部用閉包進行訪問請求
    這樣作的結果是會有不少個ajax請求在同時進行,也沒法獲得全部請求結束的時刻的鉤子jquery

  • 第三種想法(咱們老大的想法):模擬線程操做,模擬同時開啓多個線程,全部請求即設備列表放在一個線程池內(數組),每一個線程的工做,只有當本次工做完成後,才能夠繼續去線程池內去拿新任務(即發送新情求),這樣就能夠控制同時請求的個數(線程數)以及請求結束的時刻的鉤子。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>
相關文章
相關標籤/搜索