I’m trying to perform async function and then console log the results with the help of Promise. I’m afraid I haven’t quite grasped the concept yet.
getlinks performs async action. async function getLinks(param, data) { return new Promise((resolve, reject) => { let psub; var name; let g; psub = checkForPsub(param); var ultUrls = []; _.each(data, o => { title = sanitizeString(o.title); if (psub == true) { name = title + " u -- " + o.author; } else { name = title; } switch (o.domain) { case "i.imgur.com": { // downloadImgur(o,name) } break; case "imgur.com": { id = o.url.substring(o.url.lastIndexOf("/") + 1); if ( o.url.includes("https://imgur.com/a/") || o.url.includes("https://imgur.com/gallery/") || o.url.includes("http://imgur.com/a/") || o.url.includes("http://imgur.com/gallery/") ) { let urls = []; let file_name; axios .get( "https://api.imgur.com/3/album/" + id, { headers: { Authorization: "Client-ID 295ebd07bdc0ae8" } } ) .then(res => { let images = res.data.data.images; _.each(images, function(v) { var ext = v.link.split(".").pop(); if (ext == "gifv") { ext = "mp4"; } if (psub == true) { file_name = title + "--" + v.id + " " + "u--" + auth + "." + ext; } else { file_name = title + "--" + v.id + "." + ext; } let p = { url: v.link, file_name: file_name }; ultUrls.push(p); }); }) .catch(err => { console.log(err); }); } } break; case "i.redd.it": { } break; default: console.log("other", o.domain); } }); //end each return resolve(ultUrls); }); }
I wanted to wait till getlinks finished performing tasks and then console log the result.
getLinks(sub,result).then(res => console.log({res}))
But the it logs the result as empty even before the getlink is finished.
Advertisement
Answer
The simplest answer is you’re promise is resolving (return resolve(utlUrls)
) before your async code (axios.get(...).then(...)
) completes.
This is a minimal example to reproduce your problem:
let timeout = ms => new Promise(resolve => setTimeout(() => resolve(ms), ms)); async function getLinks(urls) { return new Promise((resolve, reject) => { let ultUrls = []; urls.forEach(url => timeout(500).then(res => ultUrls.push(res))) return resolve(ultUrls); }); } getLinks([1, 2, 3]).then(a => console.log(a));
It doesn’t work because we return ultUrls before we’ve filled it. We don’t wait for the timeouts to complete.
To fix this, simply wait for the promises to complete using Promise.all
. Additionally removing some unnecessary wrapping of promises, we get:
let timeout = ms => new Promise(resolve => setTimeout(() => resolve(ms), ms)); function getLinks(urls) { let ultUrls = []; let promises = urls.map(url => timeout(500).then(res => ultUrls.push(res))) return Promise.all(promises).then(a => ultUrls); } getLinks([1, 2, 3]).then(a => console.log(a));
Furthermore, if you want to use the async/await
syntax, though it doesn’t buy you much in this case where you have multiple requests in parallel, you could write it as:
let timeout = ms => new Promise(resolve => setTimeout(() => resolve(ms), ms)); async function getLinks(urls) { let ultUrls = []; let promises = urls.map(url => timeout(500).then(res => ultUrls.push(res))) await Promise.all(promises); return ultUrls; } getLinks([1, 2, 3]).then(a => console.log(a));