Home > Software design >  Pause a for loop until function is completed
Pause a for loop until function is completed

Time:02-22

I've been scratching my brain at this a majority of the day, I am attempting to download multiple files that have iterating ID's, I use a for loop to iterate and call a web request that calls a function that downloads a file.

However, I noticed files tend to get corrupted due to multiple files being requested at once, I am using the following NPM Package https://www.npmjs.com/package/nodejs-file-downloader it has alot of neat features and its also promise based.

My problem is I don't know how to use promises with the package, I would like for the loop to wait until the downloadFile() that the file was succesfully downloaded.

const axios = require('axios');
const url = require('url')
const fs = require('fs');
const DOWNLOAD_DIR = '/'
var downloadCo5mplete = false
const Downloader = require("nodejs-file-downloader");
const sleep = require('sleep-promise');

async function getFile(version)
{

  axios.request({
    url: "https://****.****.com/v1/id/*****/version/"   version,
    method: "get",
    headers:{
        ContentType: 'application/json',
        Accept: "application/json",
        Cookie: ""
    } 
  }).then(function (response) {
      const placeData = response.data.location;
      //if placeData is null, then the version is not available
      if(placeData == null)
      {
        console.log("Version "   version   " not available");
        return;
      }
      console.log("Version "   version   " available");

      downloadFile(version, placeData)
      

  }).catch(function (error) {
      //console.log(error);
  });

}



async function downloadFile(version, data)
{
  const downloader = new Downloader({
    url: data, //If the file name already exists, a new file with the name 200MB1.zip is created.
    directory: "./2506647097", //This folder will be created, if it doesn't exist.
    fileName: "2506647097 - "   version   ".rbxl",
    one rror: function (error) {
      //You can also hook into each failed attempt.
      console.log("Error from attempt ", error);
    },
  });
  
  try {
    downloader.download(); //Downloader.download() returns a promise.
    console.log("Downloaded version "   version   " successfully");
  } catch (error) {
    //IMPORTANT: Handle a possible error. An error is thrown in case of network errors, or status codes of 400 and above.
    //Note that if the maxAttempts is set to higher than 1, the error is thrown only if all attempts fail.
    console.log("Download failed", error);
  }
};


async function main()
{
  for(var i = 7990; i < 7995; i  )
  {
    await getFile(i);
  }
}

main()

Currently my console looks like this upon running the code.

Version 7990 available
Version 7991 available
Version 7992 available
Downloaded version 7990 successfully
Version 7993 available
Downloaded version 7991 successfully
Version 7994 available
Downloaded version 7992 successfully

I would like for it to look like this.

Version 7990 available
Downloaded version 7990 successfully
Version 7991 available
Downloaded version 7991 successfully
Version 7992 available
Downloaded version 7992 successfully
Version 7993 available
Downloaded version 7993 successfully
Version 7994 available
Downloaded version 7994 successfully

Apologies for the bad code, I hope somebody can help me!

-Cheers

CodePudding user response:

You should use await on your axios request

async function getFile(version)
{

  await axios.request({
    url: "https://****.****.com/v1/id/*****/version/"   version,
    method: "get",
    headers:{
        ContentType: 'application/json',
        Accept: "application/json",
        Cookie: ""
    } 
  }).then(function (response) {
      const placeData = response.data.location;
      //if placeData is null, then the version is not available
      if(placeData == null)
      {
        console.log("Version "   version   " not available");
        return;
      }
      console.log("Version "   version   " available");

      downloadFile(version, placeData)
      

  }).catch(function (error) {
      //console.log(error);
  });

}

CodePudding user response:

None of your functions justifies the async keyword (if you're not using await, using async is nonsense).

But all of your functions are missing return. You need to return the promises you create in a function.

Compare - every code path ends in return:

// returns a promise for whatever downloadFile() produces
function getFile(version) {
  return axios.request({ /* ... */ }).then((response) => {
    return downloadFile(version, response.data.location);
  }).catch(err => {
    return {error: "Download failed", version, err};
  });
}

// downloadFile() also returns a promise, so we return that
function downloadFile(version, data) {
  if (version && data) {
    const downloader = new Downloader({ /* ... */ });
    return downloader.download();
  }
  throw new Error("Invalid arguments");
};


// `downloads` will be an array of promises, we can wait for them with `Promise.all()`
function main() {
  const downloads = [];
  for (let i = 7990; i < 7995; i  ) {
    downloads.push(getFile(i));
  }
  Promise.all(downloads).then((results) => {
    // all downloads are done
  }).catch(err => {
    console.log(err);
  });
}

You probably don't want to daisy-chain the downloads. You just want to wait until all are done. Promise.all() does that.

  • Related