If you want to experiment with this concept, try running the code snippet below. Take a look at this JSFiddle for a hands-on experience.
To demonstrate how it works, I have included logs with timestamps and added a new task to the queue after the first two tasks finish (approximately 6s
).
import { once } from 'https://esm.run/lodash-es';
import PQueue from 'https://esm.run/p-queue';
import moment from 'https://esm.run/moment';
const time = moment()
function logWithTime(msg) {
console.log(`[T + ${moment().diff(time, 'ms')}ms]`, msg)
}
const wait = (t) => async () => new Promise((resolve) => {
logWithTime(`Waiting for ${t / 1000}s...`);
setTimeout(() => {
logWithTime(`Done - Waited for ${t / 1000}s`);
resolve('some result');
}, t);
});
const fetch = once(wait(5000))
const queue = new PQueue({ concurrency: 1000 });
queue.add(async function() {
logWithTime('adding 1')
const result = await fetch()
logWithTime('add1 - result')
logWithTime(result)
})
queue.add(async function() {
logWithTime('adding 2')
const result = await fetch()
logWithTime('add2 - result')
logWithTime(result)
})
setTimeout(() => {
logWithTime('adding 3')
queue.add(async function() {
const result = await fetch()
logWithTime('add3 - result')
logWithTime(result)
})
}, 6000)
(async () => {
await queue.start().onIdle();
})()
The output would show...
[T + 0ms] adding 1
[T + 0ms] Waiting for 5s...
[T + 0ms] adding 2
[T + 5001ms] Done - Waited for 5s
[T + 5002ms] add1 - result
[T + 5002ms] some result
[T + 5002ms] add2 - result
[T + 5002ms] some result
[T + 6002ms] adding 3
[T + 6002ms] add3 - result
[T + 6002ms] some result
As observed, the first two tasks are completed within about 5 seconds of each other, resulting in the fetch
function being called only once. This is supported by the fact that the logs inside the wait
function are executed just once.
Moreover, when the third task is added after the initial two are finished, it is immediately resolved without invoking the fetch (i.e., wait
) function again thanks to the memoization behavior of _.once
. Subsequent calls return the original cached result promptly.