The chaotic collision of concurrent JavaScript array concatenations causes confusion

After spending an excessive amount of time tracking down a bug, I am sharing my code with you all. Interestingly enough, I discovered that when using the push method, the array is complete. However, when using concat, there is a 50% chance that not all concatenated items will be received, as the concats appear to run simultaneously. I initially thought this was impossible. Can someone please explain why VERSION 1 works but version 2 does not?

let employments: any[] = [];
let companyIds = ['Id1', 'Id2']
await Promise.all(
    companyIds.map( async ( companyId ) => {
        const companies = await getCompaniesWithId(companyId);
        // VERSION 1
        employments.push( ...(await mergeWithOtherSource( companies )) );
        
        // VERSION 2
        employments = employments.concat( await mergeWithOtherSource( companies ));
    } )
);
// VERSION 1 consistently returns 3 expected items as found in the databases
// VERSION 2 RANDOMLY returns between 1 and 3 items
return employments.length

Answer №1

This response offers an alternative (and in my opinion, simpler) approach to achieve the same outcome. For further explanation, refer to my other response.

let companyIds = ['Id1', 'Id2']

/// Combination of await and then (some individuals may find this unfavorable)
let employments = [].concat(
   await Promise.all(companyIds.map(companyId =>
      getCompaniesWithId(companyId).then(mergeWithOtherSource)
   ))
)

/// Utilizing await only
let employments = [].concat(
   await Promise.all(companyIds.map( async ( companyId ) => {
      const companies = await getCompaniesWithId(companyId)
      return mergeWithOtherSource( companies )
   }))
)

/// Implemented in two steps
let companys = await Promise.all(companyIds.map(getCompaniesWithId)
let employments = [].concat(await Promise.all(companys.map(mergeWithOtherSource)))

// Alternative use of flat instead of concat
let employments = (await Promise.all(...)).flat()

Answer №2

The reason for this behavior is likely due to the reference of this being retrieved before its parameter is evaluated.

For example, consider the following:

// VERSION 1 step by step
// employments.push( ...(await mergeWithOtherSource( companies )) );
let O = employments
let task = mergeWithOtherSource( companies )
let items = await task;
O.push(...value) // no problem, it's always the same object
    
// VERSION 2 step by step
// employments = employments.concat( await mergeWithOtherSource( companies ));
let O = employments // multiple async thread may get the same object
let task = mergeWithOtherSource( companies )
let items = await task;
let temp = O.concat(value) // may use outdate employments
employments = temp

This means that two asynchronous functions can be executed as follows:

// VERSION 2: possible execution order
// "thread" in the sense of javascript `async`, which only one run at the same time, and only yield when `await`.

let O = employments // 1st thread
let task = mergeWithOtherSource( companies ) // 1st thread
let items = await task // 1st thread, waiting

let O = employments // 2nd thread
let task = mergeWithOtherSource( companies ) // 2nd thread
let items = await task // 2nd thread, waiting

let temp = O.concat(items) // 1st thread
employments = temp // 1st thread

let temp = O.concat(items) // 2nd thread, now using outdated employments!
employments = temp // 2nd thread, overwrite the object from thread 1


To better understand this concept, consider the statement:

GetEmployments().concat(GetSomething())

GetEmployments() is evaluated only once to produce the O mentioned in the example above.


A rough breakdown of a function call:

// step by step `x.func(y)`
let V = x
let F = V.func
let Arguments = [y]
F.apply(V,Arguments)

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

Guide on implementing short-circuit evaluation in Vue method?

Recently, I have been working with vue-cli and vuex to implement a specific functionality. Here is the code snippet that showcases my current progress: methods: { filtered() { let vol = this.$store.state.data[1].data.filter(i => i.type === 'vol& ...

Tips for avoiding automatically redirecting to the definition of a symbol for specific file types

Take this scenario: I have some AngularJs code in the file a.js: $scope.configuration.functionThatDefinedSomeWhere() With the help of this feature on WebStorm, I can easily navigate to the location where the function functionThatDefinedSomeWhere is defin ...

Conceal the iframe if the source is http:// and there is no associated

Is there a way to hide the iframe only if the src starts with "http://"? This is what I have tried so far: <script type="text/javascript> if ( $('iframe[src^="http://"]') ) document.getElementById('iframe').style.d ...

Error with importing images detected on the React/Next.js website

Recently, I encountered a frustrating bug in my React/Next JS site related to displaying images. I'm unable to show any image when using src='/static/images/service'. Even importing and assigning the route like this: import Image1 from "../ ...

Utilize jQuery to send and load double values efficiently

When attempting to load the initial .load, I am able to pass 1 variable without any issues. I receive this variable from a _GET method, store it in a data-id button attribute, and pass it back to another .load. In the second file, I once again receive the ...

Can a WordPress post category be active without being displayed on the website?

I want to showcase different categories in both full posts and post excerpts, while also using hidden categories to organize the display of posts throughout the site. For instance, I may have a 'featured' category that is assigned to various pos ...

Angular minimum JavaScript file is showing an error with the message "RangeError: Maximum call stack size exceeded"

Encountering an error in the console when navigating to URL paths users/personal or users/:id: Error message: angular.min.js:107 RangeError: Maximum call stack size exceeded. The page seems to be stuck in a loop causing it to hang indefinitely. Intere ...

empty responseText from GET request using AJAX

I've been working on a chatbox using AJAX and I've encountered an issue where my xhttp.responseText is coming back empty. In firebug, I can see that the GET request is being sent and the correct text is being returned, but for some reason it&apos ...

Using jQuery, you can enclose a string of text with HTML tags easily

This specific content within the span is being dynamically created by PHP. However, I am uncertain how to efficiently target the text string in order to begin using jQuery. <!-- input: --> <span class="price">RM1,088.00 Annually + RM10.00 Se ...

I'm looking to find the Angular version of "event.target.value" - can you help me out?

https://stackblitz.com/edit/angular-ivy-s2ujmr?file=src/app/pages/home/home.component.html I am currently working on getting the dropdown menu to function properly for filtering the flags displayed below it. My initial thought was to replicate the search ...

Exploring Angular's capabilities with filtering and handling $http promises

Having an issue with filtering data from a JSON file that contains an array of 20 objects. Within my factory, I have implemented two functions: function fetchData() { return $http .get('mock.json') .success(_handleData) ...

Encountering issues while trying to establish a connection to MongoDB through JavaScript

I have developed a code for seamlessly integrating various social networking logins with nodejs. Below is my server.js file: // include the necessary tools var express = require('express'); var app = express(); var port = process.env ...

Transforming a JSON structure into a tree model for use with the angular-tree-control component

I need help converting a complex JSON schema into a format compatible with Angular Tree Control. The issue is that the schema does not follow the required treemodel structure for Angular Tree Control, particularly because the children in the schema are not ...

Steps for generating a div, link, and image that links to another image using Javascript

Hey there, I have a cool picture to share with you! <img src="cards.png" id="img"> <!--CARD PICTURE--> Check out what I want to do with it: <div class="container_img"> <img src="cards.png" id="img"> <!--CARD PICTURE--> ...

Encrypting data using JavaScript and then decrypting it with Ruby

Looking to securely encrypt a string in a client-side JavaScript application and decrypt it on a Ruby on Rails Server. Interested in utilizing AES for encryption. What would be the most effective combination of scripts, libraries, or methods to achieve t ...

Where should the JQuery hashchange event be added for optimal placement?

I am currently utilizing the JQuery hashchange event. $(window).on('hashchange', function () { //perform certain actions }); On the initial load, if my URL includes a hash value, I know that it must be triggered by $(window).hashchange(); Is i ...

CSS Gallery Indicator: Enhancing Your Website's Visual Appeal

After implementing a CSS gallery template into my HTML code, I faced an issue. The original code contained only 4 images, but after adding nine more images, the indicator in the gallery stopped moving past the 4th image and the preview of the additional im ...

Sometimes, React doesn't cooperate properly in the callback function of a setState operation

Imagine this scenario: callback = () => { ... } When is it appropriate to use this.setState({...}, this.callback); and when should I opt for this.setState({...}, () => { this.callback(); }); In order to maintain the validity of this within the ...

Angular form not sending data when using $http.post

I have a form that is submitting to /api/tradelink, but it is not including any body or data. HTML : <form ng-submit="sendTradelink()"> <md-input-container class="md-accent"> <label>Enter your tradelink</ ...

Using jQuery, we can replace all `<span>` elements with `<img>` elements and then verify if the images have been successfully loaded

Similar Inquiry: jQuery check if image is loaded I find myself in a scenario where the following HTML structure is utilized: <div class="image"> <img class="" src="content-images/1.jpg"> <span class="slide" rel="content-images/ ...