setInterval回调执行滞后 如何获取更新后的endNode值
问题根因
和作用域没有关系,本质是JavaScript的事件循环执行规则导致的时序问题:
setInterval属于异步宏任务API,调用它的时候只是把回调函数注册到宏任务队列,不会立刻执行回调逻辑。必须等当前调用栈里所有同步代码全部执行完毕,才会按调度顺序取出队列里的异步任务执行。- 你写在
setInterval后面的变量赋值、console.log都是同步代码,注册完定时器就会立刻执行,这时候定时器回调还没开始跑,endNode自然还是初始的null值。
修改方法
把所有依赖endNode更新值的逻辑,挪到endNode被赋值的时机之后执行,也就是找到终点节点、给endNode完成赋值后,再触发打印和后续路径处理逻辑,修改后代码如下:
let endNode = null; let BFStimer = setInterval(function() { if (Q.size() > 0) { let u = Q.dequeue(); if (u.end) { $(".r" + u.x + "c" + u.y).addClass("explored"); setTimeout(function() { clearInterval(BFStimer); // 终点确认、定时器清理后,再读取endNode的值做后续处理 let currentPathNode = endNode; console.log(currentPathNode); // 后续路径回溯等所有依赖endNode的逻辑,都放在这个执行时机里 }); endNode = u; return u; } let N = u.neighbor; for (let i = 0; i < N.length; i++) { if (N[i].isWall) { continue; } if (N[i].status === "undiscovered") { N[i].status = "discovered"; $(".r" + N[i].x + "c" + N[i].y).addClass("discovered"); N[i].parent = u; N[i].distance = u.distance + 1; Q.enqueue(N[i]); } } $(".r" + u.x + "c" + u.y).addClass("explored"); } }, 5);
提示:如果后续依赖
endNode的逻辑比较多,可以把这部分逻辑封装成独立函数,在endNode赋值完成后调用即可。核心原则就是:需要等待异步任务返回结果的逻辑,不能写在同步执行流里,必须放到异步任务的回调中触发。
内容的提问来源于stack exchange,提问作者abbcccdddd
相关产品推荐
相关产品推荐

