Reputation: 148
I'm working on a project where I use some promises/timeout to delay the call of different functions.
the code of this project is a bit big, so I thought it might be better to make a sample of it and test it and find the reason that is causing the promise ( only last one ) to not resolve.
After making a sample of this code, the same bug that was happening to me occurred again, so it's when I knew that there's something wrong in my logic and wanted to seek some help:
I'll write the code below and explain it after:
let i = 0; // declaring i which help us recall the test method (until a given length)
//function 1 2 and 3 are 3 functions that take few seconds to resolve ( made it simpler for you guys
// to understand my problem
function function1() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 1");
res();
}, 1000);
});
}
function function2() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 2");
res();
}, 1000);
});
}
//in function 3 if the i didn't reach the length given ( made static here=10) it will finish its code
// then call the test method with the new/incremented i
// this keep happening until i= the required length(10) where the function will return true
// and when the function 3 return back true.. the test function should resolve and call the final()
// function
function function3(i) {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 3");
if (i + 1 == 10) {
res({ bool: true });
} else {
i++;
res({ bool: false, i: i });
}
}, 2000);
});
}
function final() {
console.log("final");
}
function test(i) {
return new Promise((res, rej) => {
function1().then((data) => {
function2().then((data) => {
function3(i).then((data) => {
console.log("boolean: ", data.bool);
if (data.bool) {
console.log("true..so if");
res();
} else {
console.log("false..so else");
test(data.i);
}
});
});
});
}); //end of promise
}
test(i).then(() => {
final();
});
the code runs well and it prints few times consecutively:
from function 1
from function 2
from function 3
....
and here is where the final function should be called to print "final" but its not. while debugging, I noticed that the function 3 return back false 9 times and true in the last one and this true should cause the test function to resolve but its not.
Upvotes: 0
Views: 61
Reputation: 370729
Right now, in the case of the else
, you have a dangling Promise not connected to anything else:
} else {
console.log("false..so else");
test(data.i);
}
The currently running test
function never has its res
called after the recursive call, so it remains unresolved forever, so the initial call of
test(i).then(() => {
final();
});
never results in final
running.
While you could fix it by adding test(data.i).then(res)
, to ensure the Promises are all connected:
let i = 0; // delaring i wich help us recall the test method (until a given length)
//function 1 2 and 3 are 3 functions that take few seconds to resolve ( made it simpler for you guys
// to understand my problem
function function1() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 1");
res();
}, 100);
});
}
function function2() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 2");
res();
}, 100);
});
}
//in function 3 if the i didnt reach the length given ( made static here=10) it will finish its code
// then call the test method with the new/incremented i
// this keep happening until i= the required length(10) where the function will return true
// and when the function 3 return back true.. the test function should resolve and call the final()
// function
function function3(i) {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 3");
if (i + 1 == 10) {
res({ bool: true });
} else {
i++;
res({ bool: false, i: i });
}
}, 200);
});
}
function final() {
console.log("final");
}
function test(i) {
return new Promise((res, rej) => {
function1().then((data) => {
function2().then((data) => {
function3(i).then((data) => {
console.log("boolean: ", data.bool);
if (data.bool) {
console.log("true..so if");
return res();
} else {
console.log("false..so else");
test(data.i).then(res);
}
});
});
});
}); //end of promise
}
test(i).then(() => {
final();
});
It would be much better to avoid the explicit Promise construction antipattern, and avoid the Promise-as-callback antipattern. This can be done concisely by making test
an async
function:
async function test(i) {
await function1();
await function2();
const data = await function3(i);
console.log("boolean: ", data.bool);
if (data.bool) {
console.log("true..so if");
return;
} else {
console.log("false..so else");
await test(data.i);
}
}
let i = 0; // delaring i wich help us recall the test method (until a given length)
//function 1 2 and 3 are 3 functions that take few seconds to resolve ( made it simpler for you guys
// to understand my problem
function function1() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 1");
res();
}, 100);
});
}
function function2() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 2");
res();
}, 100);
});
}
//in function 3 if the i didnt reach the length given ( made static here=10) it will finish its code
// then call the test method with the new/incremented i
// this keep happening until i= the required length(10) where the function will return true
// and when the function 3 return back true.. the test function should resolve and call the final()
// function
function function3(i) {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 3");
if (i + 1 == 10) {
res({ bool: true });
} else {
i++;
res({ bool: false, i: i });
}
}, 200);
});
}
function final() {
console.log("final");
}
async function test(i) {
await function1();
await function2();
const data = await function3(i);
console.log("boolean: ", data.bool);
if (data.bool) {
console.log("true..so if");
return;
} else {
console.log("false..so else");
await test(data.i);
}
}
test(i).then(() => {
final();
});
Or, if you have to keep using .then
s:
function test(i) {
return function1()
.then(function2)
.then(() => function3(i))
.then((data) => {
console.log("boolean: ", data.bool);
if (data.bool) {
console.log("true..so if");
return;
} else {
console.log("false..so else");
return test(data.i);
}
});
}
let i = 0; // delaring i wich help us recall the test method (until a given length)
//function 1 2 and 3 are 3 functions that take few seconds to resolve ( made it simpler for you guys
// to understand my problem
function function1() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 1");
res();
}, 100);
});
}
function function2() {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 2");
res();
}, 100);
});
}
//in function 3 if the i didnt reach the length given ( made static here=10) it will finish its code
// then call the test method with the new/incremented i
// this keep happening until i= the required length(10) where the function will return true
// and when the function 3 return back true.. the test function should resolve and call the final()
// function
function function3(i) {
return new Promise((res, rej) => {
setTimeout(() => {
console.log("from function 3");
if (i + 1 == 10) {
res({ bool: true });
} else {
i++;
res({ bool: false, i: i });
}
}, 200);
});
}
function final() {
console.log("final");
}
function test(i) {
return function1()
.then(function2)
.then(() => function3(i))
.then((data) => {
console.log("boolean: ", data.bool);
if (data.bool) {
console.log("true..so if");
return;
} else {
console.log("false..so else");
return test(data.i);
}
});
}
test(i).then(() => {
final();
});
Whenever you have a Promise, you should almost always return
it, or be the initial asynchronous operation of the script.
Upvotes: 1