Last active
November 1, 2018 18:26
-
-
Save Istar-Eldritch/5fb7f44ff16714f4707f78e091d634c6 to your computer and use it in GitHub Desktop.
Trampolining "memory leak" on ES6 recursive promise resolve chain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const promiseYoullWork = () => Promise.resolve(); | |
async function job(todo: number, iterations: number = 0): Promise<number> { | |
// Print memory consumption of the process every 10k iterations | |
if (iterations % 10000 === 0) { | |
const memUsage = process.memoryUsage(); | |
const mem = (memUsage.heapTotal / 1024 / 1024); | |
console.log(`i: ${iterations / 1000}k`, `mem: ${Math.round(mem * 100) / 100} Mb`); | |
} | |
if (iterations === todo) { | |
return iterations; | |
} else { | |
await promiseYoullWork(/* Request to the database */); | |
return job(todo, iterations + 1); | |
} | |
} | |
job(1000000) | |
.then((iterations) => { | |
console.log(`Finished after ${iterations} iterations`); | |
}) | |
.catch(console.error); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface FT<I, O> extends Function { | |
(...args: I[]): O; | |
} | |
interface FN<I, O> extends FT<I, Promise<FN<I, O> | O>> {} | |
function trampolineP<I, O>(f: FN<I, O>): (...args: any[]) => Promise<O> { | |
return async function _trampoline(/*arguments*/): Promise<O> { | |
let result = await f.apply(f, Object.values(arguments)); | |
while (result instanceof Function) { | |
result = await result(); | |
} | |
return result; | |
}; | |
} | |
const promiseYoullWork = () => Promise.resolve(); | |
async function job(todo: number, iterations: number = 0): Promise<any> { | |
// Print memory consumption of the process every 10k iterations | |
if (iterations % 10000 === 0) { | |
const memUsage = process.memoryUsage(); | |
const mem = (memUsage.heapTotal / 1024 / 1024); | |
console.log(`i: ${iterations / 1000}k`, `mem: ${Math.round(mem * 100) / 100} Mb`); | |
} | |
if (iterations >= todo) { | |
return iterations; | |
} else { | |
await promiseYoullWork(/* Request to the database */); | |
return () => job(todo, iterations + 1); | |
} | |
} | |
const trampolinedJob = trampolineP(job); | |
trampolinedJob(1000000) | |
.then((iterations: any) => { | |
console.log(`Finished after ${iterations} iterations`); | |
}) | |
.catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment