Skip to content

Instantly share code, notes, and snippets.

@XoseLluis
Last active May 17, 2020 17:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save XoseLluis/e92d84a6e23adb4b868849455a61e296 to your computer and use it in GitHub Desktop.
Save XoseLluis/e92d84a6e23adb4b868849455a61e296 to your computer and use it in GitHub Desktop.
Avoiding to overfill the stack thanks to setTimeout
const smallValue = 100;
const largeValue = 50000;
function factorial(n) {
return (n !== 0) ? n * factorial(n - 1) : 1;
}
function tailFactorial(n, total = 1) {
//console.trace();
if (n === 0) {
return total;
} // proper tail call
return tailFactorial(n - 1, n * total);
}
function runFactorial(factorialFn){
let res = factorialFn(smallValue);
console.log("factorial: " + res);
//stack overflow:
try {
res = factorialFn(largeValue);
console.log("factorial: " + res);
}
catch (ex){
console.log("Exception: " + ex.message);
//Maximum call stack size exceeded
}
}
[factorial, tailFactorial].forEach(fn => runFactorial(fn));
//for both functions we get a max stack exception, so node no longer implements TCO
//--------------------------
function factorialWithTimeoutAndPromise(n, total = 1, resFn){
//initial call
if (resFn === undefined){
var pr = new Promise((res, rej) => resFn = res);
}
if (n === 0){
resFn(total);
}
else{
setTimeout(() => factorialWithTimeoutAndPromise(n-1, n * total, resFn), 0);
}
return pr;
}
function factorialWithTimeoutAndPromiseImproved(n, total = 1, counter = 0, resFn){
//initial call
if (resFn === undefined){
var pr = new Promise((res, rej) => resFn = res);
}
if (n === 0){
resFn(total);
}
else{
if (counter < 50){
factorialWithTimeoutAndPromiseImproved(n-1, n * total, ++counter, resFn);
}
else{
setTimeout(() => factorialWithTimeoutAndPromiseImproved(n-1, n * total, 0, resFn), 0);
}
}
return pr;
}
(async() => {
console.log("-- using Timeout");
let options = [
{
name: "Not optimized",
value: smallValue,
fn: factorialWithTimeoutAndPromise
},
{
name: "Not optimized",
value: largeValue,
fn: factorialWithTimeoutAndPromise
},
{
name: "Optimized",
value: smallValue,
fn: factorialWithTimeoutAndPromiseImproved
},
{
name: "Optimized",
value: largeValue,
fn: factorialWithTimeoutAndPromiseImproved
}
];
for (let option of options) {
console.log(option.name + " factorial for: " + option.value);
let start = Date.now();
let result = await option.fn(option.value);
console.log("result: " + result);
console.log("it took " + (Date.now() - start) + "\n");
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment