例如,采用以下代码:
const fetch = _.once(myRealFetch)
const queue = new PQueue({concurrency: 1000});
queue.add(function() {
const result = fetch()
// Rest of the code ...
})
queue.add(function() {
const result = fetch()
// Rest of the code ...
})
await queue.start().onIdle();
它声明了一个
fetch
函数,该函数被记忆以使用 Lodash 的 _.once
函数运行一次。
然后我继续创建一个 PQueue,将调用
fetch
的 2 个函数添加到队列中,然后运行它。
现在让我们假设
myRealFetch
需要 5 秒才能运行,因为我使用 concurrency > 1
运行它,这意味着两个函数之一将首先调用它,并且很可能第二个函数也会调用它。
此时第一次调用还没有结束,那么第二次调用会返回什么呢?
有内置的方法来处理这个问题吗?
您可以使用下面的代码自行测试。这是一个 JSFiddle,你可以玩一下看看会发生什么。
我添加了一些带有时间戳的日志,并在前 2 个任务完成后将另一个项目添加到队列中(大约
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(`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();
})()
最终的输出将是...
[T + 0ms] adding 1
[T + 0ms] Waiting for 5s...
[T + 0ms] adding 2
[T + 5001ms] 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
您可以看到前 2 个在 5 秒左右几乎是立即解析的,因此
fetch
只被调用 once。 wait
函数中的日志仅被调用一次也证明了这一点。
然后,在前 2 个任务解析后添加的第 3 个任务将立即返回,而不调用 fetch (即
wait
)函数。因此,应用了 _.once
,并且对 fetch 方法的任何其他调用都会立即返回原始的记忆结果。