如何让一个函数只在另一个函数完成时运行?(循环中的setTimeout)



我试图找到一种简单、直接的方法,让第二个函数在第一个函数完成后运行。我尝试了一些我在网上遇到的建议,但这些特定函数的操作似乎有所不同,因为它们在for循环中设置了Timeouts。到目前为止,我所尝试的一切都会导致第二个函数在第一个函数完成之前运行(即更新页面上的一些颜色样式(。

const [VisitedNodes, setVisitedNodes] = useState([]);  
const [ShortestPath, setShortestPath] = useState([]);
// runs first
function drawVisitedNodes() {
for (let i = 0; i < VisitedNodes.length; i++) {
const node = VisitedNodes[i];
setTimeout(() => {
document.getElementById(`${node.x}-${node.y}`).className =
"node-visited";
}, i);
}
drawShortestPath();
}
// runs second
function drawShortestPath() {
for (let i = 0; i < ShortestPath.length; i++) {
const node = ShortestPath[i];
setTimeout(() => {
document.getElementById(`${node.x}-${node.y}`).className =
"node-shortPath";
}, i * 10);
}
}
<button 
onClick={drawVisitedNodes}>Visualize
</button>

您可以尝试以下操作:

const [VisitedNodes, setVisitedNodes] = useState([]);  
const [ShortestPath, setShortestPath] = useState([]);
// runs first
function drawVisitedNodes() {
let x= 0;
for (let i = 0; i < VisitedNodes.length; i++) {
const node = VisitedNodes[i];
setTimeout(() => {
document.getElementById(`${node.x}-${node.y}`).className =
"node-visited";
}, i);
x++;
}
setTimeout(() =>  drawShortestPath(), x);
}
// runs second
function drawShortestPath() {
for (let i = 0; i < ShortestPath.length; i++) {
const node = ShortestPath[i];
setTimeout(() => {
document.getElementById(`${node.x}-${node.y}`).className =
"node-shortPath";
}, i * 10);
}
}
<button 
onClick={drawVisitedNodes}>Visualize
</button>

这将给第二个函数的执行增加一些延迟。多少时间?x会告诉你,因为在for的末尾,它将是VisitedNodes.length。是的,你也可以这样做:

setTimeout(() =>  drawShortestPath(), VisitedNodes.length)

所以,为了让你知道为什么这是有效的,我给你举下一个例子:

  • VisitedNodes状态是一个由4个元素组成的数组
  • CCD_ 5状态是一个由2个元素组成的数组
  • 单击该按钮将执行drawVisitedNodes()功能

在您的情况下,执行将是:

  1. setTimeout(() => codeForNode1, 0)
  2. setTimeout(() => codeForNode2, 1)
  3. setTimeout(() => codeForNode3, 2)
  4. setTimeout(() => codeForNode4, 3)
  5. drawShortestPath()

但是,由于setTimeout的原因,实际执行将是:

  1. drawShortestPath()
  2. codeForNode1
  3. codeForNode2
  4. codeForNode3
  5. codeForNode4

根据我的建议,您的代码将保持秩序。让我们看看:

  1. setTimeout(() => codeForNode1, 0)
  2. setTimeout(() => codeForNode2, 1)
  3. setTimeout(() => codeForNode3, 2)
  4. setTimeout(() => codeForNode4, 3)
  5. setTimeout(() => drawShortestPath(), 4)

最终执行将是:

  1. codeForNode1
  2. codeForNode2
  3. codeForNode3
  4. codeForNode4
  5. drawShortestPath()

在评论中,您问我为什么使用实际数字不起作用。好吧,我的答案是,这取决于你有多少VisitedNodes。使用我刚才给你的例子,如果你使用x < 4,它不会起作用,因为你试图在执行codeForNode4之前执行drawShortestPath()函数,所以在这种情况下你混合了执行。但是,如果您设置x ≥ 4,它将按您的预期工作。

您可以使用await等待所有逻辑完成

像这样

async function foo() {
for (let i = 0; i < VisitedNodes.length; i++) {
const node = VisitedNodes[i];
setTimeout(() => {
document.getElementById(`${node.x}-${node.y}`).className =
"node-visited";
}, i);
}
}
function drawVisitedNodes() {
await foo();
drawShortestPath();
}
// runs second
function drawShortestPath() {
for (let i = 0; i < ShortestPath.length; i++) {
const node = ShortestPath[i];
setTimeout(() => {
document.getElementById(`${node.x}-${node.y}`).className =
"node-shortPath";
}, i * 10);
}
}

最新更新