Perform a fetch request within a map function or loop

I'm currently working on iterating over an array of objects. Depending on the content of some of those objects, I need to execute a fetch function and wait for the result before updating the new array.

Below is my JavaScript code:

const allPosts = [
{
    // Object details here...
},
// Additional object details...
];

let filteredPosts = [];
const output = document.querySelector('.output');
const parser = new DOMParser();

const setPostsByType = () => {
  let doc;
  let videoThumbnail = '';
  
  for (let i = 0; i < allPosts.length; i++) {
      const item = allPosts[i];
      
      if (item.body) {
          doc = parser.parseFromString(item.body, 'text/html');
      }
      
      if (item.type.includes('video')) {
          let videoID = doc.querySelector('a')?.getAttribute('href')?.split('vimeo.com/')[1] 
              || doc.querySelector('[data-url]')?.getAttribute('data-url')?.split('vimeo.com/')[1];
              
          if (videoID && videoID.includes('?')) {
              videoID = videoID.split('?')[0];
          }

          console.log(videoID);
          
          fetch(`https://vimeo.com/api/v2/video/${videoID}.json`)
              .then((response) => {
                  return response.text();
              })
              .then((data) => {
                  const { thumbnail_large } = JSON.parse(data)[0];
                  videoThumbnail = thumbnail_large + '.jpg';
                  console.log(videoThumbnail);
                  return videoThumbnail; // Asynchronous
              })
              .catch((error) => {
                  console.log(error);
              });
      }
      
      const postObject = {
          id: item.id,
          post_id: `postid__${item.id}`,
          body: item.body,
          video_thumbnail_id: videoThumbnail,
          type: item.type,
          tags: item.tags,
          date: item.date
      };
      
      filteredPosts.push(postObject);
  }
};

setPostsByType();
output.textContent = JSON.stringify(filteredPosts, null, 4);
<pre class="output"></pre>

Apologies for the lengthy snippet. It's already a filtered set of data. For more information and a larger dataset, you can visit this JSFIDDLE link: https://jsfiddle.net/lharby/wrLpheok/.

The issue arises from the asynchronous nature of the fetch call. The ids of each video post get logged to the console after pushing to the filteredPosts array.

Several attempts have been made to address this issue:

  • Enclosing everything within an async function.
  • Creating a function that should return the postObject and executing it inside the fetch .then() function (however, this is wrapped in an if statement filtering items based on post type).
  • Using a map instead of a for loop.

While there are solutions where users want to call a fetch API endpoint first and then map items, the situation here is different. The fetch function can only be called after iterating through each post body and meeting specific conditions.

Your assistance would be greatly appreciated.

Answer №1

Utilizing async/await will enhance the readability and manageability of your code. It's recommended to steer clear of using .then() for intricate logic.

const result = await Promise.all(items.map(async item => {...}));
is a widely-used method to convert an array with async operations into a new one.

If you encounter a scenario where there's no item.body, consider calling doc.querySelector on an undefined doc.

const output = document.querySelector('.output');
const parser = new DOMParser();

const setPostsByType = () => {
  return Promise.all(allPosts.map(async item => {
      let videoThumbnail = null;
      if (item.type.includes('video')) {
          const doc = parser.parseFromString(item.body ?? '', 'text/html');
          let videoID = doc.querySelector('a')?.getAttribute('href')?.split('vimeo.com/')[1] 
          ||
          doc.querySelector('[data-url]')?.getAttribute('data-url')?.split('vimeo.com/')[1];
          if (videoID && videoID.includes('?')) {
              videoID = videoID.split('?')[0];
          }
          try{
            const [{thumbnail_large}]  = await fetch(`https://vimeo.com/api/v2/video/${videoID}.json`).then(r=>r.json());
            videoThumbnail = thumbnail_large + '.jpg';
          }catch(e){ console.log(e) }
      }
      return {
          id: item.id,
          post_id: `postid__${item.id}`,
          body: item.body,
          video_thumbnail_id: videoThumbnail, // this remains empty due to asynchronous fetching
          type: item.type,
          tags: item.tags,
          date: item.date
      }
  }));
};

setPostsByType().then(filteredPosts => {
  output.textContent = JSON.stringify(filteredPosts, null, 4);
});
<pre class="output"></pre>
<script>
// Code snippet
</script>

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

Using Kendo TabStrip to dynamically include HTML files as tabs

In the process of creating a web-part that mirrors a Kendo tabstrip, I've managed to integrate a simple ul with external html files linked to each relative li using JavaScript. The functionality works smoothly up until this point. However, my current ...

React's setInterval acting unpredictably

Creating a stopwatch functionality in React was my recent project. To achieve updating the number every second, I implemented setInterval as follows: import React, {useEffect, useState, useRef} from 'react'; const MAX_TIMER = 5; export defa ...

Struggling with D3.js Angular CLI where Scope disappears within the tick() function?

Hey everyone, I'm currently in the process of incorporating a D3 visualization network graph into an Angular CLI project (http://bl.ocks.org/mbostock/1153292) using the ng2-nvd3 component. Here's the Angular component: import { Component, OnIn ...

What could be the reason for the base64 returned by url-loader in webpack appearing to be

After downloading and including the url-loader for Webpack, my configuration looks like this: loaders: [ { test: /.jsx?$/, include: path.join(__dirname, './public/scripts'), loader: 'babel-loader', exclude: /node_modul ...

The process of selecting particular words from a data-attribute value

Is it possible to extract specific words from a data attribute in a web application while preserving spaces? I am looking to: Select the first word Select the last word Select the word that precedes... Select the word that follows... Select everything t ...

The specified function is not recognized within the HTMLButtonElement's onclick event in Angular 4

Recently diving into Angular and facing a perplexing issue: "openClose is not defined at HTMLButtonElement.onclick (index:13)" Even after scouring through various resources, the error seems to be rooted in the index page rather than within any of the app ...

Navigating Next.js: Mastering the art of localStorage Access

Currently, I am developing my first member area using next.js. My goal is to store some data in localStorage (such as token, expiresAt, userInfo), which will eventually be moved to an http-only cookie. The code below is generating the error: "LocalStorage ...

What is the best way to create a reusable component for a dialog box or modal window?

I have been working on developing a reusable dialog component with a yes or no button at the bottom. The main idea behind this is to create a user confirmation dialog that prompts the user to confirm their entered information before proceeding. import Re ...

Learn how to retrieve data from a JSON server in Angular 8 and then sort that data in a table by utilizing checkboxes

Currently, I'm in the middle of an Angular project where I could use some assistance on how to filter data through checkboxes within a table. The setup involves a home component that displays data from a JSON server in a tabular format using a service ...

Unlocking the power of accessing nested data in JSON files dynamically

Building a new feature that allows users to input a word, choose the language, and receive the definition along with an example using the API service. To retrieve the desired data at position 0 of "exclamation" in the "meaning" section. This ensures that ...

Error in Internet Explorer when attempting to close a Fancybox iframe that plays a YouTube video

Even the FancyApps page itself contains the error mentioned below. If you visit using Internet Explorer 9, for example, follow these steps: Go to Internet Options > Advanced > Disable script debugging (Internet Explorer). Then click on the YouTube ( ...

Any ideas on how to format a date for jQuery Datepicker?

Currently, I have implemented two different datepickers on my website, but I am interested in switching to jQuery's Datepicker for a more unified solution. Here is the current format that I am sending to our backend API: However, I would prefer to i ...

"Enhancing user interaction with Vue.js through the stunning ripple effect on

Is there a way to customize the ripple effect from this source so that it doesn't always have to be a DIV? Here's an example: Currently, when I implement it like this: <ripple class="btn">send</ripple> It works as expected, but as ...

Issue with handling click events on action column in Datatable using jQuery

Utilizing jquery datatable with an action column containing "edit" and "delete" links. The table populates correctly, but encountering an issue when trying to open a bootstrap modal form upon clicking the edit button within the table. However, the modal do ...

What is the best way to correctly render several React components using a single index.js file?

I am facing an issue with rendering two React component classes. One class creates a counter and works fine, while the other class generates a simple string wrapped in HTML tags but does not render. I have tried various tutorials to troubleshoot this probl ...

In PHP/HTML, if the URL is domain.co.uk/?debug, then the following action will

Apologies for what may seem like a basic question, but I've been searching for a clear answer with no luck! My goal is simple - when someone goes to , I want to show extra details, like the code version or any other notes I include. Once again, sorr ...

Leveraging Three.js Raycaster for a seamless PDF download functionality

Is there a way to trigger a PDF download when clicking on a 3D object in a Three.js scene? Below is an example of how I have set up the Raycaster: var raycaster; var mouse = { x: 0, y: 0 }; init(); function init() { raycaster = new THREE.Raycaster() ...

Tips for selecting React component props based on a specific condition

Here is a React component that I have: <SweetAlert show={this.props.message} success title={this.props.message} onConfirm={this.props.handleCloseAlert}> </SweetAlert> Upon using this component, I receive the following alert ...

What is the best way to identify which JavaScript code is triggering or managing an event?

In the development of an HTML5 application framework designed for businesses to use on their intranet and extranet sites, a SAP JEE application server is utilized. The framework incorporates the grid system known as "Semantic UI" along with various JavaScr ...

Navigate through the components of an array within HTML

I am a beginner in HTML and I need to customize a specific piece of code to suit my requirements. Here is the code snippet written in pseudo code: <app-myapp *ngIf="true" [exclude] = "[this.myUser.id]" ...