node.jsasync-awaitpromisefetch

nodejs promise return before the execution of the function


I am trying to call fetch method in the promise.allSettled. But the method return the value as empty. fetch is taking time and the response is returned before.

Desired result: I want all the images base64 in the array. But it is returning as empty.

There is the code.

(async function getData() {
                    results = results.recordset;
                        let i = 0;
                        const result = await Promise.allSettled(results.map(async (record) => {
                            (async function getData() {
                                var file = record.Path.split('Images');
                                //file = file[1].replaceAll('\\','/');
                                var file_path = file[1].replaceAll('\\', '/') + "/" + record.FileName;
                                var img_url = "localhost"+file_path;
                                let file_data_response = await reportModel.fetchTiff(img_url);
                                let base64Image = Buffer.from(file_data_response, 'binary').toString('base64');
                                let imgSrc = "data:png;base64,"+base64Image;
                                //let imgSrc = '';
                                let imgImg = '<img src='+img_url+' alt="Remote Image" />';
                                console.log(imgImg);
                                response.img.push(imgImg);
                            })();
                        })).then((results) => {
                                                        
                        });
                    
                    return resolve(response);
                })();

exports.fetchTiff = function(image_url) {
    return new Promise((resolve, reject) => {
        var response = 0;
        (async function getData() {
            // let responsezz  = await axios.get(image_url, {responseType: 'arraybuffer'});//.then(res => {return resolve(res);})
            // response = await responsezz.data;
            let responsezz  = await fetch(image_url);
            response = await responsezz.blob();
            console.log(response);
            return resolve(response);
        })();
        
    });
}

Solution

  • Took an initiative to rewrite your code for better readability.

    Main Function to Fetch and Process Images: The fetchAndProcessImages function processes each image record, fetches the image, converts it to base64, and then creates an HTML image tag. It also returns the object with an array of images you intend to retrieve.

    async function fetchAndProcessImages(results) {
      const response = { img: [] };
      results = results.recordset;
    
      // Using Promise.allSettled to handle each record asynchronously
      const fetchPromises = results.map(async (record) => {
        try {
          // Construct the image URL
          const imgUrl = constructImageUrl(record);
    
          // Fetch and convert the image to base64
          const base64Image = await fetchImageAsBase64(imgUrl);
    
          // Construct the image HTML and push it to the response
          const imgTag = createImageTag(base64Image);
    
          response.img.push(imgTag);
    
          return { status: "fulfilled", value: imgTag };
        } catch (error) {
          console.error(
            `Error processing image for record ${record.FileName}:`,
            error
          );
          return { status: "rejected", reason: error.message };
        }
      });
    
      await Promise.allSettled(fetchPromises);
    
      console.log("All images processed:", response.img);
      return response;
    }
    

    Helper Functions:

    Constructing an image URL:

    function constructImageUrl(record) {
      const filePath = record.Path.split("Images")[1].replace(/\\/g, "/");
      return `http://localhost${filePath}/${record.FileName}`;
    }
    

    Converting to base64: Converting an image to a base64 string using a buffer involves first fetching the image as an array buffer for binary representation. Then function converts this binary data into a base64-encoded string, allowing it to be embedded directly in HTML

    async function fetchImageAsBase64(url) {
      const response = await fetchTiff(url);
      const arrayBuffer = await response.arrayBuffer();
      return Buffer.from(arrayBuffer).toString("base64");
    }
    

    Separate function to extract image tag creation:

    function createImageTag(base64Image) {
      return `<img src="data:image/png;base64,${base64Image}" alt="Remote Image" />`;
    }
    

    And fetching image: This function ensures that any HTTP errors during the fetch are caught and logged properly. It’s crucial for diagnosing issues with remote image URLs.

    async function fetchTiff(imageUrl) {
      try {
        const response = await fetch(imageUrl);
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response;
      } catch (error) {
        console.error(`Error fetching image from ${imageUrl}:`, error);
        throw error;
      }
    }
    

    The full code example:

    // Main function to fetch and process image data
    async function fetchAndProcessImages(results) {
      const response = { img: [] };
      results = results.recordset;
    
      // Using Promise.allSettled to handle each record asynchronously
      const fetchPromises = results.map(async (record) => {
        try {
          const imgUrl = constructImageUrl(record);
          const base64Image = await fetchImageAsBase64(imgUrl);
          const imgTag = createImageTag(base64Image);
          response.img.push(imgTag);
          return { status: "fulfilled", value: imgTag };
        } catch (error) {
          console.error(
            `Error processing image for record ${record.FileName}:`,
            error
          );
          return { status: "rejected", reason: error.message };
        }
      });
    
      await Promise.allSettled(fetchPromises);
      console.log("All images processed:", response.img);
      return response;
    }
    
    // Helper functions
    function constructImageUrl(record) {
      const filePath = record.Path.split("Images")[1].replace(/\\/g, "/");
      return `http://localhost${filePath}/${record.FileName}`;
    }
    
    async function fetchImageAsBase64(url) {
      const response = await fetchTiff(url);
      const arrayBuffer = await response.arrayBuffer();
      return Buffer.from(arrayBuffer).toString("base64");
    }
    
    function createImageTag(base64Image) {
      return `<img src="data:image/png;base64,${base64Image}" alt="Remote Image" />`;
    }
    
    async function fetchTiff(imageUrl) {
      try {
        const response = await fetch(imageUrl);
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response;
      } catch (error) {
        console.error(`Error fetching image from ${imageUrl}:`, error);
        throw error;
      }
    }