Почему моя рекурсивная функция с обещаниями ждет только один раз?
Я пытаюсь визуализировать проблему "Ханойская башня" и пытался использовать обещания, чтобы заставить функции ждать анимацию движения одного диска (которую я смоделировал с помощью setTimeout), прежде чем продолжить решение проблемы. Этот тест-код вычисляет правильные движения, но только один раз ждет анимацию и сразу же выплевывает остальные:
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;
}
Для людей, не знающих проблемы, я немного упростил код, по сути, цель состоит в том, чтобы напечатать "перемещение" семь раз с задержкой в одну секунду между каждым из них:
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;
}
1 ответ
Проблема в том, что вы немедленно вызываете все свои вызовы, а затем передаете их возвращаемые значения в качестве аргумента .then()
, Что вам нужно сделать, это передать функции .then()
которые называют их вместо:
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')
Но вы можете сделать его еще проще, используя async
а также 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')