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", onError: 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
Advertisement
Answer
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.