Javascript多執行緒+JQuery Defered(非同步物件)動態載入大量元素到Dom

Javascript多執行緒+非同步應用動態載入大量元素到Dom

     /**
     *【jQuery】deferred物件介紹及使用deferred物件解決ajax非同步問題
     * https://www.gss.com.tw/blog/jquery%E9%80%9A%E9%81%8Edeferred%E7%89%A9%E4%BB%B6%E7%AE%A1%E7%90%86ajax%E9%9D%9E%E5%90%8C%E6%AD%A5
     */
    var deferred = $.Deferred(),
        deferred2 = $.Deferred(); 

    var isCircleClick = false;
    // Worker
    if (window.Worker) {        
        var all = data.allGraph.length;
        var curt = 0;
        var loadingMsg = $("app-loading span").text();



        /********************** multithread go go go **********************/
        var numWorkers = 10;//執行緒數量
        var workers = [];
        var chunkCount = Math.floor(all / numWorkers);//整數除法
        var deferred3s = [];//JQuery的非同步物件陣列
        console.log(`[svgDraw] start time [thread count:${numWorkers}] => ${new Date()}`);

        for (var i = 0; i < numWorkers; i++)
        {
            if (i == numWorkers - 1)
            {//最後一個執行緒把餘數全部處理掉
                var modValue = all % numWorkers;
                if (modValue > 0)
                {
                    chunkCount += modValue;
                }                
            }

            var chunkData = data.allGraph.splice(0, chunkCount);            

            /*
                new Worker('assets/localhost_env_js/drawPCBWorker.js');//本機worker.js
                new Worker('../Areas/Viewer/Scripts/drawPCBWorker.js');//uat worker.js
            */
            var drawWorker = new Worker(drawPCBWorkerUrl);//宣告新執行緒,drawPCBWorkerUrl為執行緒要執行的工作流程.js                    
            workers.push(drawWorker);

            var deferred3 = $.Deferred();//建立JQuery非同步物件
            deferred3s.push(deferred3);

            //執行執行緒工作流程
            drawWorker.postMessage([chunkData, basicStrokeWidth]);

            (function (i, deferred3) {
	            //接收執行緒工作流程的回傳
                drawWorker.onmessage = function (e) {

                    for (var i = 0; i < e.data.length; i++) {

                        /*
                         *錯誤範例!!!!!
                         *絕對不能+=1這樣累計,會嚴重拖累迴圈效能!!!!!      
                        //curt += 1;	
                        //$("app-loading span").html(`${loadingMsg}${curt}/${all}`)
                        */

                        var combinGroup = myDocument.createElementNS(svgNS, "g");

                        setAttributes(combinGroup, {
                            "id": e.data[i].refdes,
                            "stroke": (e.data[i].PN == "" ? getLevelData("REFDES", "NOASSEMBLED").ColorCode : getLevelData(e.data[i].mainClass, e.data[i].subClass).ColorCode),
                            "class": e.data[i].mainClass + " " + e.data[i].subClass + (e.data[i].PN == "" ? " NOASSEMBLED" : ""),
                            "style": getLevelData(e.data[i].mainClass, e.data[i].subClass).Display == true ? 'display:inline;' : 'display: none;',
                            "bom": (e.data[i].mainClass != "VIA" ? e.data[i].Bom : ""),
                            "partnumber": (e.data[i].mainClass != "VIA" ? e.data[i].PN : ""),
                            "data-val": e.data[i]["data-val"],
                            "bWidth": e.data[i].bWidth,
                            "bHeight": e.data[i].bHeight,
                            "notice": e.data[i].notice ? e.data[i].notice : ""

                        });

                        if (e.data[i].mainClass === "VIA") {
                            combinGroup.setAttribute("data-test", e.data[i].isTestVia);
                            if (e.data[i].isTestVia !== undefined && e.data[i].isTestVia === false && my.showAllVia === false) {
                                combinGroup.setAttribute("class", combinGroup.getAttribute("class") + " none");
                            }
                        }

                        for (var j = 0; j < e.data[i].items.length; j++) {
                            for (var graph in e.data[i].items[j]) {
                                var dom = myDocument.createElementNS(svgNS, graph)
                                setAttributes(dom, e.data[i].items[j][graph]);

                                if (graph === "circle") {
                                    var circle = dom;

                                    circle.addEventListener("mousedown", function (e) {
                                        isCircleClick = true;
                                    });
                                    circle.addEventListener("dblclick", function (e) {
                                        getNetLineData(this.getAttribute("net"));
                                    }, false);
                                }

                                combinGroup.appendChild(dom);                                
                            }
                        }
                        group.appendChild(combinGroup);
                    }
                    
                    curt += e.data.length;
                    $("app-loading span").html(`${loadingMsg}${curt}/${all}`)
                    deferred3.resolve();
                }
            })(i, deferred3);
        }        

        $.when.apply($, deferred3s).done(function () {
            //等待所有JQuery非同步物件都完成工作
            deferred.resolve();
            console.log(`[svgDraw] end time => ${new Date()}`);
        });
        /********************** multithread end **********************/


    }

 


ChatGPT範例

Qestion:javascript es3 多執行緒搭配jquery deferred如何使用

在 JavaScript ES3 环境中,无法直接使用现代 JavaScript 特性(例如 letconst),但可以通过 Web Workers 实现多线程,并使用 jQuery Deferred 来管理异步操作。以下是一个示例,展示如何在 ES3 环境中使用 Web Workers 和 jQuery Deferred 进行多线程处理:

示例代码

Web Worker 文件 (worker.js)

javascript

self.onmessage = function(event) {
    var data = event.data;
    var result = 0;

    // 假设进行一些计算,这里仅做示范
    for (var i = data.start; i < data.end; i++) {
        result += i;
    }

    // 将结果发送回主线程
    self.postMessage(result);
};

主线程代码 (main.js)

javascript

$(document).ready(function() {
    var numWorkers = 10;
    var totalIterations = 100000;
    var iterationsPerWorker = totalIterations / numWorkers;
    var workers = [];
    var deferreds = [];
    var results = [];
    var i;

    // 创建 Web Workers 并分配任务
    for (i = 0; i < numWorkers; i++) {
        var worker = new Worker('worker.js');
        workers.push(worker);

        var deferred = $.Deferred();
        deferreds.push(deferred);

        worker.postMessage({ start: i * iterationsPerWorker, end: (i + 1) * iterationsPerWorker });

        (function(i, deferred) {
            worker.onmessage = function(event) {
                results[i] = event.data;
                deferred.resolve();
            };
        })(i, deferred);
    }

    // 使用 $.when.apply 方法处理 Deferred 数组
    $.when.apply($, deferreds).done(function() {
        var totalResult = 0;
        for (i = 0; i < results.length; i++) {
            totalResult += results[i];
        }
        console.log('All workers have completed their tasks.');
        console.log('Total result:', totalResult);
    });
});

解释

Web Worker 文件 (worker.js)

  • self.onmessage:处理从主线程接收到的消息。
  • 在接收到消息后执行计算,然后使用 self.postMessage 将结果发送回主线程。

主线程代码 (main.js)

  • 创建 10 个 Web Workers,每个 Worker 处理总循环的一部分。
  • 使用 $.Deferred() 创建 Deferred 对象,并将它们添加到 deferreds 数组中。
  • 使用 postMessage 将循环范围分配给每个 Worker,并在 Worker 完成任务后解决对应的 Deferred。
  • 使用 $.when.apply($, deferreds).done 等待所有 Deferred 对象完成,然后计算总结果并输出。

通过这种方式,您可以使用 Web Workers 实现多线程处理,并使用 jQuery Deferred 来管理异步操作和回调。这种方法在需要处理大量数据或执行复杂计算的情况下,可以提高性能。