简体   繁体   中英

JavaScript run one function after another

I am trying to create a visual selection sort. finMin() will go through the array one by one displaying the new min when found. I want to use this function in a loop for selection sort. If the function is run one time, then everything is fine, but if findMin() is run in a loop, then the function has bugs.

If a function is run in a loop such as for(let i=0; i<3; i++){findMin();} does the second iteration of the loop run immediately or does it wait for findMin to return before i == 1 ? I believe that this loop should be sequential, but I do not know why the code does not work in a loop then.

 var gBars = []; var gSelected = 19; var gFinished = 19; var changed = false; var step = 0; function Bar(index, height){ this.index = index; this.height = height; this.getIndex = function(){ console.log(this.index); }; this.getHeight = function(){ console.log(this.height); }; this.getStats = function(){ console.log(this.index + ' ' + this.height); } this.setHeight = function(h){ this.height = h; } this.setIndex = function(i){ this.index = i; } } function insertAfter(newNode, referenceNode){ referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } function setHeight(i, h){ document.getElementById(i).style.height = h + 'em'; } function addBar(i, h){ //base case i = 0 //first bar if(i === 0){ var currentDiv = document.getElementById("root"); d = document.createElement('div'); d.setAttribute("id", 'block'+i); d.setAttribute("class", 'block'); gBars[i] = new Bar(i, h); currentDiv.appendChild(d); setHeight('block'+i,h); } else { let last = i-1; var currentDiv = document.getElementById('block'+last); d = document.createElement('div'); d.setAttribute("id", 'block'+i); d.setAttribute("class", 'block'); gBars[i] = new Bar(i, h); insertAfter(d, currentDiv); setHeight('block'+i,h); } } function selSort(){ for(let i=0; i<10; i++){ findMin(gFinished); } } function findMin(gFinished) { let min = gBars[gFinished].height; //start at 18 because bars are rotated 180deg //go backwards so it appears to go forwards var delay = 500; let i = gFinished - 1; min = setTimeout(timeout(i, min), delay); return min; } function timeoutchange(){ var swapped = document.getElementById('block'+gFinished); var selected = document.getElementById('block'+gSelected); let temp = gBars[gFinished].height; swapped.style.height = gBars[gSelected].height + 'em'; selected.style.height = temp + 'em'; selected.style.backgroundColor = "grey"; var selected = document.getElementById('block'+gFinished); selected.style.backgroundColor = "green"; gFinished--; var selected = document.getElementById('block'+gFinished); selected.style.backgroundColor = "blue"; gSelected = gFinished; } function timeout(i, min) { console.log("Next loop: " + i); if(i==18){ var selected = document.getElementById('block19'); selected.style.backgroundColor = "blue"; } if(min > gBars[i].height) { min = gBars[i].height; var selected = document.getElementById('block'+i); selected.style.backgroundColor = "blue"; console.log('new min ' + min); selected = document.getElementById('block'+gSelected); selected.style.backgroundColor = "grey"; gSelected = i; } i--; if (i == 0) { console.log("End"); var swapped = document.getElementById('block'+gFinished); swapped.style.backgroundColor = "red"; setTimeout(function(){ return timeoutchange(); },1000) step++; return min; } else { setTimeout(function(){ return timeout(i, min); },500) } } function init(){ for(let i=0; i<20; i++){ let ran = Math.floor(Math.random() * 50 + 1); gBars[i] = new Bar(i,ran); addBar(i,ran); } for(let i=0; i<20; i++){ gBars[i].getStats(); } //works findMin(gFinished); //findMin does not work in loop //why? //selSort(); return; } init();
 .selected{ background-color:blue; } .block{ border:1px solid rgba(0,0,0,.4); width:20px; background-color:grey; } #root{ display:flex; transform:rotate(180deg); position:absolute; left:10%; }
 <html> <head> <link rel="stylesheet" href="style.css"> </head> <body> <button>sort</button> <div id="root"></div> </body> <script src="selectionsort.js"></script> </html>

What you want to do is use JavaScript Promises. ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise ) There you have a concept called chaining so that you can chain your functions one after the other based on execution (in this case resolved). For an example Let say you have to functions:

function a() {
  setTimeout( function() {
    resolve("Success!")  // Yay! Everything went well!
  }, 250) 
}  

function b() {
  setTimeout( function() {
    resolve("Success 2!")  // Yay! Everything went well!
  }, 250) 

}

you can make these promises and chain them one after the other:

let a = new Promise((resolve, reject) => {
  setTimeout( function() {
    resolve("Success!")  // Yay! Everything went well!
  }, 250) 
}) 

let b = new Promise((resolve, reject) => {
  setTimeout( function() {
    resolve("Success2!")  // Yay! Everything went well!
  }, 250) 
})


let c = new Promise((resolve, reject) => {
  setTimeout( function() {
    resolve("Success3!")  // Yay! Everything went well!
  }, 250) 
})

a().then(()=>{
   return b();
}).then(()=>{
   return c();
}); 

setTimeout returns a number representing the id of the timer, so when running findMin() in a loop it will return that, and immediately after execute the next iteration.

To make the loop wait for the timeout you'll have to await for a promise that is resolved after the delay

for (let i = 0; i < 3; i++) {
  min = await new Promise((resolve) => {
    setTimeout(() => {
      resolve(timeout(i, min))
    }, 500);
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM