You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript结合SigmaJS实现算法可视化时UI刷新仅在函数末尾执行

问题根因

浏览器采用单线程事件循环模型运行JavaScript,界面重绘、DOM更新这类渲染任务,必须等当前同步调用栈完全清空、主线程空闲时才会执行。你的代码刚好卡在这个机制上:

  • 你写的sleep是忙等实现:靠while循环空转占满CPU,执行期间主线程完全被占死,浏览器根本没机会处理渲染任务
  • 整个算法流程全是同步代码:从点击按钮触发Dijkstra()开始,到算法遍历完所有节点结束,全程占着主线程。你调用的s.refresh()、createQueue()虽然已经修改了内存里的图数据、更新了DOM节点内容,但浏览器腾不出手把这些变更绘制到屏幕上,所有更新都会被攒到算法完全跑完后一次性渲染,自然看不到中间执行步骤。
    断点调试时显示正常也很好解释:断点会强制挂起JS执行,把主线程交还给浏览器,浏览器就能趁这个间隙完成中间状态的渲染。
修复步骤

核心思路是把同步阻塞的算法逻辑改成异步非阻塞模式,每执行完一步就把主线程还给浏览器完成渲染,等渲染、延迟结束后再跑下一步。

  1. 替换错误的忙等sleep
    把原来空转占线程的sleep换成基于setTimeout的异步实现,不要阻塞主线程:
    sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    
  2. 改造算法相关方法为异步函数
    所有涉及算法执行、需要等待延迟的方法都加async关键字,调用异步方法、sleep时前面加await:
    首先改启动入口:
    async function onStartClick(){
        if(radio === 'p') await graphe.Prim();
        if(radio === 'd') await graphe.Dijkstra(0);
    }
    
    再改造Dijkstra和遍历方法,参考你现有代码的适配示例:
    async Dijkstra(start){
        this.tabVisited = [];
        this.tabRencontred = [];
        for(var i = 0; i < Object.keys(this.adjacencyList).length; i++){
            this.tabVisited.push(false);
            this.tabRencontred.push(false);
        }
        await this.visiterPriorite(start);
    }
    
    async visiterPriorite(sommetCourant) {
        if(!this.tabVisited[sommetCourant])
        {
            var priorityQueue = new PriorityQueue();
            priorityQueue.enqueue(sommetCourant, 0);
            var csChar = Object.keys(this.adjacencyList)[sommetCourant];
    
            s.graph.nodes().forEach(n => {
                if(n.id === csChar)
                {
                    n.color = "grey";
                }
            });
            s.refresh();
            createQueue(priorityQueue.items)
            // 等待指定延迟,期间主线程空闲,浏览器可以完成当前状态渲染
            await this.sleep(500);
    
            while(!priorityQueue.isEmpty())
            {
                // 此处保留你原有的出队、遍历邻接节点、更新距离的逻辑
                // 注意:每次修改节点状态、更新优先队列、调用s.refresh()之后
                // 都要加await this.sleep(单步停留时长),保证每一步都能被渲染
            }
        }
    }
    
注意事项
  • 所有调用sleep的位置必须加await,否则异步sleep不会按预期等待
  • Prim算法也按照同样的逻辑改造为异步即可
  • 绝对不要用while空转的方式实现延迟,这种写法会卡死整个页面,不光动画出不来,还会导致页面无响应。

内容的提问来源于stack exchange,提问作者michjea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:18:34