Potential issue with Lodash's _.once function: the possibility of a race condition

Here's an example of code that demonstrates a scenario:

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(); 

In this code snippet, a fetch function is defined and memoized to run only once using Lodash's _.once.

A PQueue is created, and two functions are added to the queue, both invoking the fetch function.

If myRealFetch takes 5 seconds to run and there's concurrency set above 1, then one function will invoke it first and likely the second function will also try to invoke it before the first completes.

So, what happens when the second invocation occurs before the first one finishes?

Is there a built-in solution to manage this situation?

Answer №1

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.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How do I determine whether an object is a Map Iterator using JavaScript?

I'm working on some NodeJS code that involves a Map Iterator object. How can I accurately determine if a Javascript object is a "Map Iterator"? Here are the methods I have attempted: typeof myMap.keys() returns 'Object' typeof myMap.keys() ...

Change a Character or Word in JavaScript after it's been typed

If I were to type the word "hello" into a textarea, is there a way for me to select that specific word and modify it afterwards? For instance, let's say I typed hello without hitting the space bar; could the system recognize this word and automaticall ...

Issue with D3.js call() Method

I am in the process of constructing a D3JS chain that concludes with a .call() function. Below is my current chain: foo.selectAll('svg') .data(data) .enter() .append('svg') .classed('someclass', true) .cal ...

The handlebar does not undergo any modifications once the authentication process is completed

This file is named header.hbs <!doctype html> <html class="no-js" lang=""> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>{{ title }}</title> ...

Leveraging client API callback variables within a Node.js backend system

If I send a request on the client side using the code snippet below public/foo.js function bar() { fetch('https://api.github.com/') .then(response => response.json()) .then(data => { console.log(data) }) .catch( ...

Conceal a card once verified within a bootstrap modal upon successful AJAX completion

On my delete page, there are multiple posts with a delete button. When the delete button is clicked, a Bootstrap modal opens asking for confirmation "Are you sure you want to delete this post? YES : NO" If the YES button is clicked, the .click(function(e) ...

Unable to locate module in node_modules directory when attempting to import an image into TS

In my .tsx file, I am encountering an issue with the following code snippet: import L from 'leaflet'; import icon from 'leaflet/dist/images/marker-icon.png'; import iconShadow from 'leaflet/dist/images/marker-shadow.png'; The ...

Failure to trigger Ajax callback function

I am currently working on a form page that will be submitted using Ajax. The steps I have planned are: 1. Use Ajax to check if the email already exists 2. Verify if the passwords match 3. Switch to another "screen" if they do match 4. Final ...

Access the value of a submitted form using jQuery, when there are multiple forms with identical class names

I've looked for a solution here but couldn't find one that meets my needs. I have multiple forms with the class name .sbt-form: <form class='sbt-form'> <input name='kord' val=1/> </form> <form class= ...

What are some recommended methods in Angular for developing reusable panels with both controller and view templates?

I am still getting acquainted with angularjs, so there might be something I'm overlooking, but I'm struggling to find an efficient way to create reusable views that can be instantiated within a parent view. My specific scenario involves a web ap ...

Node.js readline: SyntaxError: Unexpected token =>

Currently, I am diving into node.js and have found myself in need of utilizing the readline module for a new project. Below is the code snippet that I extracted directly from the official readline module example. const readline = require('readline&ap ...

Tips for generating a .csv document using data from an array?

I am currently utilizing a PHP class to validate email addresses in real-time. The PHP Script is functioning as expected: validating the emails and displaying the results on the same page by generating a <td> element for each validated email. Howeve ...

The element you are trying to access, "noUiSlider," does not belong to the type "HTMLElement" and cannot be found

Running into a roadblock here. What mistake am I making? .... /// <reference path="../../../typings/tsd.d.ts" /> var slider:HTMLElement = document.getElementById('slider'); noUiSlider.create(slider, { start: +$input.val(), step: + ...

Dealing with missing image sources in Angular 6 by catching errors and attempting to reset the source

When a user adds a blob to my list, sometimes the newly added image is still uploading when the list is refreshed. In this case, I catch the error and see the function starting at the right time: <img src="https://MyUrl/thumbnails/{{ blob.name }}" widt ...

Problem Encountered with Jquery Validation for Name Field (Restriction to Alphabetic

I am struggling to validate a name format using a predefined jQuery validation tool. My intention is for the name field to accept only characters, but even with the correct regex pattern, it still allows numbers to be entered. The specific script I am us ...

"The variables in the .env file are not reflecting the latest updates. What is the best way

Currently, I am in the process of developing an application using Quasar (Vue) where I have stored my database keys in a .env file. Recently, I encountered an issue when attempting to switch to another instance and updating the keys in the env file. Despit ...

"Run JavaScript code within the boundaries of the start and end of XMLHttpRequest

Currently, I am using XMLHttpRequest to execute an AJAX request without the use of jQuery, relying solely on plain old Javascript. This particular AJAX request may take some time as it calls an endpoint responsible for processing transactions. In order to ...

Extracting data from a JSON response and presenting it within a div element, using a weather API

Looking to parse json data in order to extract information from the json response, specifically the values of weather.main and weather.description and then display them inside a div. Below is the sample json response along with the accompanying JavaScript/ ...

Concealing an item in an Angular Ionic repeater

I am creating a customizable list control where users can filter through different data levels. This list control consists of 4 hierarchical levels with numerous items. Initially, only the first level item is displayed. Upon clicking on the first level, th ...

Trilateration of three-dimensional points using K vertices on each face

I'm currently working on a project using Three.js and I have a set of 3D points in the form of (x, y, z) coordinates, as well as a series of faces. Each face consists of K points and can be either convex or concave in shape. Despite consulting the doc ...