Reputation: 538
I've trying to find an easy, straightforward way to get the second function to run after the first one finishes. I've tried some suggestions I've come across online but these particular functions seem to operate differently due to the fact that they have setTimeouts within for-loops. Everything I've tried so far causes the second function to run before the first one is finished doing its thing (which is to update some color styling on the page).
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>
Upvotes: 0
Views: 55
Reputation: 338
You can try something like this:
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>
This will add some delay to the execution of the second function. How much time? The x
will tell you, because at the end of the for
it will be VisitedNodes.length
. Yes, you can also do it like this:
setTimeout(() => drawShortestPath(), VisitedNodes.length)
So, just to give you an idea of why this works, I’m gonna give you the next example:
VisitedNodes
state is an array of 4 elements.ShortestPath
state is an array of 2 elements.drawVisitedNodes()
function.In your case, the execution will be:
setTimeout(() => codeForNode1, 0)
setTimeout(() => codeForNode2, 1)
setTimeout(() => codeForNode3, 2)
setTimeout(() => codeForNode4, 3)
drawShortestPath()
But, because of the setTimeout’s, the actual execution will be:
drawShortestPath()
codeForNode1
codeForNode2
codeForNode3
codeForNode4
With what I recommend you, your code will keep the order. Let’s see:
setTimeout(() => codeForNode1, 0)
setTimeout(() => codeForNode2, 1)
setTimeout(() => codeForNode3, 2)
setTimeout(() => codeForNode4, 3)
setTimeout(() => drawShortestPath(), 4)
The final execution will be:
codeForNode1
codeForNode2
codeForNode3
codeForNode4
drawShortestPath()
In the comments, you asked me why using an actual number doesn’t work. Well, my answer is that it depends on the amount of VisitedNodes
that you have. Using the example I just gave you, if you use x < 4
it won’t work, because you are trying to execute the drawShortestPath()
function before codeForNode4
gets executed, so you are mixing the executions in that case. But if you set an x ≥ 4
it will work as you expect.
Upvotes: 1
Reputation: 1134
you can use await
to wait till all the logic done
like this
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);
}
}
Upvotes: 0