使用Lodash的_.once函数时的竞争条件

问题描述 投票:0回答:1

例如,采用以下代码:

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
运行它,这意味着两个函数之一将首先调用它,并且很可能第二个函数也会调用它。

此时第一次调用还没有结束,那么第二次调用会返回什么呢?

有内置的方法来处理这个问题吗?

javascript typescript lodash race-condition
1个回答
0
投票

您可以使用下面的代码自行测试。这是一个 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 方法的任何其他调用都会立即返回原始的记忆结果。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.