Data within an array can become compromised when passing through a complex series of nested asynchronous arrow

This discussion thread delves into the intricacies of sync versus async operations and offers potential solutions. However, despite implementing one of the suggested solutions, I continue to encounter errors. I believe I have reached my limit in understanding ES here, and I am in dire need of assistance as I cannot comprehend why this issue persists. Below is the code snippet from my nuxt project, which I migrated from a backend built on express.

async fetch({store, error}) {
  let series = '', courses = [], album = {}
  store.state.courses.forEach(async course => {
    album = {...course}
    series = course.uri.split('/')[2]
    try {
     const {data: {data}} = await axios.get('http://localhost:3000/luvlyapi/videos', {
      params: {
        series  //? album id
      }
    })
    album['videos'] = data
    courses.push(album)
    console.log('loop', courses)
  } catch (err) {
    error({statusCode: err.statusCode, message: err})
  }
})
console.log({courses})
store.commit('SET_COURSES', courses)

} https://i.sstatic.net/4zZ0z.jpg

Despite pushing elements into the array within the loop, it remains empty once the loop concludes.

Answer №1

.forEach() doesn't pause for your asynchronous callback. It simply continues through its loop while you log the value of courses, and later when all the await operations inside your callback finish, the values are added to courses. This timing issue arises when you're accessing the variable before it's populated with data.

It's important to note that await only pauses the local function execution (the closest function scope), in this case, the .forEach() callback. It does not cause any higher-level processes to pause. Since .forEach() doesn't check what your callback returns, it doesn't consider the promise returned by the async callback's completion. Consequently, once you reach the await, the async callback returns a promise while the .forEach() loop proceeds to the next iteration even though the await inside the callback isn't finished yet.

Remember, await only halts the local function, not anything above or outside it. When your async function hits an await, it returns a promise to the outer world. To halt everything including the caller functions, some action must be taken on that promise which .forEach() doesn't do.

In contrast, a for loop keeps the await within the actual function, pausing the entire scope with the await. If you require a loop to pause with an await, opt for a for loop over a .forEach() loop.

For instance, consider this code:

async fetch({store, error}) {
    let series = '',  courses = [],  album = {};
    for (let course of store.state.courses) {
        album = {...course}
        series = course.uri.split('/')[2]
        try {
            const {data: {data}} = await axios.get('http://localhost:3000/luvlyapi/videos', {
                params: {
                    series //? album id
                }
            })
            album['videos'] = data
            courses.push(album)
            console.log('loop', courses)
        } catch (err) {
            error({
                statusCode: err.statusCode,
                message: err
            })
        }
    }
    console.log({courses})
    store.commit('SET_COURSES', courses)
}

Additionally, there's an issue in your original implementation regarding sharing higher-level scoped variables among concurrent async callbacks, leading one to overwrite another. The remedy involves either serializing the async calls as demonstrated in my example or defining the variables locally within the async scope to give each async callback its own separate variables.

Answer №2

When trying to implement Promise.all in your code, follow these steps:

async fetch({ store, error }) {
  let series = '', courses = [], album = {}
  let pr = store.state.courses.map(course => {
    return new Promise(resolve => {
      album = { ...course }
      series = course.uri.split('/')[2]
      try {
        const { data: { data } } = await axios.get('http://localhost:3000/luvlyapi/videos', {
          params: {
            series  //? album id
          }
        })
        album['videos'] = data
        courses.push(album)
        console.log('loop', courses)
        resolve();
      } catch (err) {
        error({ statusCode: err.statusCode, message: err })
      }
    })
  });

  await Promise.all(pr);

  console.log({ courses })
  store.commit('SET_COURSES', courses)
}

If you encounter issues with await inside forEach loop not waiting, for more information visit this link

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

Tips for verifying that an input field only accepts values from an array in Angular 6

In this specific scenario, the input fields are only supposed to accept values that exist in a pre-defined array. If any other values are entered, an error should be triggered. .component.html <input type="text" ([ngModel])="InputValues& ...

Place an image in the middle of a div with text aligned to the right side

How do I center an image within a div that has text on the right side? The page layout is based on percentages and I want the image to be perfectly centered with the text floated to the right. This is what I currently have: IMG.logo { display: block ...

Omit words from list in a route in Express.js

When working with the Express.js Framework, I am faced with a scenario where I have the following route defined: app.post('/:username/:slug', user.fn); I am now looking for a solution to create a regular expression that can validate if the slug ...

How can I trigger an Onclick event from an <a tag without text in a Javascript form using Selenium?

Here is my original source code: <a onclick="pd(event);" tabindex="0" issprite="true" data-ctl="Icon" style="overflow: hidden; background: transparent url("webwb/pygridicons_12892877635.png!!.png") no-repeat scroll 0px top; width: 16px; height: 16px ...

Unable to activate the navbar toggle feature on Bootstrap 4.0

****I have started working with bootstrap 4.0, but I am facing issues with the navbar toggle functionality. Even after trying to copy code from the official documentation and using the current alpha version of bootstrap, the toggle is not working as expe ...

When trying to gather multiple parameters using @Param in a NestJS controller, the retrieved values turn out

Can someone help me understand why I am struggling to retrieve parameters using the @Param() decorators in my NestJS controller? These decorators are defined in both the @Controller() decorator argument and the @Get() argument. I am relatively new to Nest ...

issue with mongoose virtual populate (unable to retrieve populated field)

During my project using mongoose with typescript, I encountered an issue with adding a virtual called subdomains to populate data from another collection. Although it worked without any errors, I found that I couldn't directly print the populated data ...

Issues arise when the ViewBag does not update

At the moment, I have implemented some inline javascript on my webpage. This javascript makes an ajax call to a partial view controller in order to update the ViewBag along with it. However, it appears that the data is not updating as expected. The informa ...

The execution of Node.js on data is triggered only after the content has been successfully written

Hello, I am attempting to establish a connection to a telnet server using Node's net library. const net = require('net'); const con = new net.Socket(); con.connect(23,'10.0.0.120', () => { console.log('Telnet connected ...

Converting a JSON array into an object representation

I have received some JSON data that has a specific structure: [ { "items": [ { "id": "xxxx", "description": { "style": "", "specs": "" } }, { "id": ...

Looking for a more efficient method to pass components with hooks? Look no further, as I have a solution ready for

I'm having trouble articulating this query without it becoming multiple issues, leading to closure. Here is my approach to passing components with hooks and rendering them based on user input. I've stored the components as objects in an array an ...

Using jQuery to append an <option> element to a <select> tag

Every time I try to add an option to a select, the option I want to add gets appended to the first option instead of the actual select element. $(".ct [value='']").each(function() { $(this).append($("<option></option>").attr("val ...

React Material UI - All radio buttons within a list can be individually selected

I'm looking to create a set of Radio Buttons for each element in my array. While my project is functioning well overall, I'm having issues with the radio buttons as they are all selectable at once. ...

Safari not updating Angular ng-style properly

I created a simple carousel using Angular and CSS animations which works well in Chrome. However, I recently tested it in Safari and noticed that the click and drag functionality does not work. I've been trying to fix this issue for days and could use ...

dynamically assigning a style attribute based on the dimensions of an image retrieved from a URL

My aim is to determine whether or not I should use an image based on its dimensions. To achieve this, I came across a function on stack overflow that can retrieve the dimensions of an image just by using its URL. Here is the code snippet they provided: f ...

A guide on updating content within curly braces when a user inputs into a React form

Currently, I am facing an issue with a string that is supposed to include my name as {{firstName}}. I have an input box where the user can type, and I want to replace the {{firstName}} placeholder with the input value as the user types. The problem arise ...

What to do when the 'image' property in Next.js next/image has an implicit 'any' type and needs fixing?

I'm a newcomer to Next.js and TypeScript and I can't seem to find any helpful resources on resolving this particular issue: import Image from 'next/image'; export default function Item({ image }) { // <-- parameter image needs a &ap ...

The data type 'unknown' cannot be directly converted to a 'number' type in TypeScript

After developing a type for my click handle functions that should return a value with the same type as its parameter, I encountered the following code: type OnClickHandle = <T extends unknown = undefined>(p: T extends infer U ? U : T) => ...

Using Vue to dynamically set custom validation messages

I am currently tackling the challenge of modifying the default invalid text for form inputs with the code snippet provided below. The method I am attempting works when the text is static, but the text in my case must be dynamic, requiring a prop/data value ...

Toggle the flag status of a checkbox based on the response provided in dialogues (Angular)

Query: I am facing an issue with my checkbox system where a dialog pops up when trying to unflag a form by unchecking the box. The dialog asks for confirmation before removing the form. How can I ensure that the checkbox remains checked until the user clic ...