Why does my recursive function with promises only wait once?

Bonsai

I'm trying to visualize the "Tower of Hanoi"-problem and tried using promises to make the functions wait for one disc's movement to be animated (which I simulated with setTimeout) before continuing to solve the problem. This test-code calculates the correct movements, but only waits for the animation once and then spits out the rest immediately:

    var A = "rod A";
    var B = "rod B";
    var C = "rod C";

    solve(3,A,C,B);

    function solve (n,source,target,spare) {
        var promise = new Promise(function(resolve,reject){
            if (n==1) {
                setTimeout(function(){
                    console.log("move a disc from "+source+" to "+target);
                    resolve();
                },1000);
            }
            else {
                        solve(n-1,source,spare,target)
                .then(  solve( 1 ,source,target      )  )
                .then(  solve(n-1,spare,target,source)  )
                .then(  resolve()                       );
            }
        });
        return promise;
    }

For people not knowing the problem, I simplified the code a bit, essentially the goal is to print "move" seven times with one second of delay between each of them:

    solveTest(3);

    function solveTest (n) {
        var promise = new Promise(function(resolve,reject){
            if (n==1) {
                setTimeout(function(){
                    console.log("move");
                    resolve();
                },1000);
            }
            else {
                        solveTest(n-1)
                .then(  solveTest( 1 )  )
                .then(  solveTest(n-1)  )
                .then(  resolve()       );
            }
        });
        return promise;
    }
Patrick Roberts

The problem is you are immediately invoking all of your calls, and then passing their return values as an argument to .then(). What you need to do is pass functions to .then() that call them instead:

function sleep (ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms)
  })
}

function solve (n, source, target, spare) {
  if (n === 1) {
    return sleep(1000).then(function () {
      console.log('move a disc from ' + source + ' to ' + target)
    })
  } else {
    return solve(n - 1, source, spare, target).then(function () {
      return solve(1, source, target, spare)
    }).then(function () {
      return solve(n - 1, spare, target, source)
    })
  }
}

solve(3, 'rod A', 'rod B', 'rod C')

But you can make it even easier to read by using async and await:

const sleep = ms => new Promise(resolve => { setTimeout(resolve, ms) })

async function solve (n, source, target, spare) {
  if (n === 1) {
    await sleep(1000)
    console.log(`move a disc from ${source} to ${target}`)
  } else {
    await solve(n - 1, source, spare, target)
    await solve(1, source, target, spare)
    await solve(n - 1, spare, target, source)
  }
}

solve(3, 'rod A', 'rod B', 'rod C')

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related