Promise.all with "nested" axios request - javascript

I'm facing a small problem with Promise.all and axios. I read a lot of documentation on "how to do it", but still I did not get what I want.
Basically, I want to execute multiple axios requests and when they all finished, I want to do something…
My code is:
async ajaxPromise() {
let me = this;
const someFunction = () => {
return new Promise(resolve => {
setTimeout(() => resolve('222'), 100)
})
}
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
debugger;
await callback(array[index], index, array);
}
}
let urlObjects = ["https://url1.com", "https://url2.com", "https://url3.com"];
let requestArr = [];
await asyncForEach(urlObjects, async (data) => {
let waitForThisData = await someFunction(data);
requestArr.push(
axios.get(data)
.then(function (response) {
console.log("THEN AXIOS")
})
.catch(function (response) {
console.log("CATCH AXIOS")
})
);
});
Promise.all([
requestArr
])
.then(function (results) {
console.log("THEN PROMISE")
})
.finally(() => {
console.log("FINALLY PROMISE")
})
.catch(function (error) {
console.log("CATCH PROMISE")
});
},
What happens, is console.log("THEN PROMISE") is displayed before all the console.log("THEN AXIOS"). What I would like to do: display the console.log("THEN PROMISE") after the console.log("THEN AXIOS").
Where am I wrong ?
Thanks for your help.

Related

async keyword not working on function using node js

I don't know why i am getting this error
uncaughtException: await is only valid in async function
as i am using async keyword at getChild function still i am getting this error
my code:
async function filterFile(folderPath) {
try {
wantExt = [".jpg"];
let parts;
const paths = await checkFileLoc(folderPath, 3);
const otherFiles = [];
for (const filePath of paths) {
parts = filePath.split("/");
let splitFileName = parts[parts.length - 1].split(".");
if (wantExt.includes(`.${splitFileName[splitFileName.length - 1]}`)) {
otherFiles.push(filePath);
}
}
let ignoreFile = otherFiles.filter((x) =>
x.endsWith("_bio.jpg")
);
let test = otherFiles.filter((x) => !ignoreZipFile.includes(x));
return { test };
} catch (error) {
console.log("error:", error);
}
}
async function getChild(parents) {
return new Promise(function (resolve, reject) {
Shop.findAll({
where: {
shop_no: parents.id,
},
attributes: ["id", "name"],
})
.then((children) => {
let gotValue= await filterFile(children);
console.log(gotValue);
resolve(children);
})
.catch(function (err) {
reject(err);
});
});
}
and if i remove async from the function then I am getting gotValue as promise don't know how to get value
Try adding async to callback function in findAll
async function getChild(parents) {
return new Promise(function (resolve, reject) {
Shop.findAll({
where: {
shop_no: parents.id,
},
attributes: ["id", "name"],
})
.then(async (children) => { // Add it here
let gotValue= await filterFile(children);
console.log(gotValue);
resolve(children);
})
.catch(function (err) {
reject(err);
});
});
}
You missed async keyword before
(children) => {
let gotValue = await filterFile(children);
console.log(gotValue);
resolve(children);
}
function. It should be
async (children) => {
let gotValue = await filterFile(children);
console.log(gotValue);
resolve(children);
}
"await is only valid in async function"
Exactly as the error says, await is used inside an async function.
const fn = async () => { await someAsyncFunction() };
So in your scenario, make the callback async as well to await the filterFile code.
.then(async (children) => {
let gotValue= await filterFile(children);
console.log(gotValue);
resolve(children);
})
async function filterFile(folderPath) {
try {
wantExt = [".jpg"];
let parts;
const paths = await checkFileLoc(folderPath, 3);
const otherFiles = [];
for (const filePath of paths) {
parts = filePath.split("/");
let splitFileName = parts[parts.length - 1].split(".");
if (wantExt.includes(`.${splitFileName[splitFileName.length - 1]}`)) {
otherFiles.push(filePath);
}
}
let ignoreFile = otherFiles.filter((x) =>
x.endsWith("_bio.jpg")
);
let test = otherFiles.filter((x) => !ignoreZipFile.includes(x));
return { test };
} catch (error) {
console.log("error:", error);
}
}
async function getChild(parents) {
try {
const children = await Shop.findAll({
where: {
shop_no: parents.id,
},
attributes: ["id", "name"],
});
let gotValue= await filterFile(children);
console.log(gotValue);
return children;
} catch(err) {
throw(err);
}
}

JavaScript - replace setTimeout with async / await

First, I know this is a common question. I'm trying to get a handle on how to use async / await in place of setTimeouts, but all the examples I see online use a setTimeout to simulate the async. This throws me off when it's a set timeout that I'm trying to replace.
In the function below, I want this.filteredResultsto await the results of an API call before trying to filter those results and assign it to this.filteredResults.
getResults() {
let allResults= airtableQuery.getTable("Transfers"); // API call using imported 'getTable' function
console.log(allResults); // returns full array â–¶[] although it's not available for filtering yet.
setTimeout(() => { // I want to replace this timeout
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
}, 250); // random ms that is roughly how long airtableQuery takes for the API call.
},
And the airtableQuery:
getTable(table) {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
}
}
);
return recordsArr;
},
Please make the outer function an async function and then await the results before filtering them.
async function getResults() {
let allResults = await airtableQuery.getTable("Transfers");
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
},
Given that getTable() is not a Promise, await will not do anything. For that reason, we can make getTable() return a Promise which will resolve with recordsArr.
getTable(table) {
return new Promise((resolve, reject) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
reject(err)
}else {
resolve(recordsArr)
}
}
);
})
}
Hope it helps.
i always likes primise,this my code show you
getTable(table) {
return new Promise((res, rej) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
res(recordsArr)
},
function done(err) {
if (err) {
this.$toasted.error(err);
rej(err)
}
}
);
})
}
getResults() {
airtableQuery.getTable("Transfers").then(res => {
let allResults = res
console.log(allResults);
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
});
}

async await retry log after all retries

How can I console.log if it still fails after all retries done? and console.log if it succeeds, using async-retry package:
const retry = require('async-retry');
async function updateDB(updateUser) {
await retry(async () => {
const res = await updateUser;
if (/* some error after finishing all retries*/) {
console.log('failed');
}
console.log('Success');
}, {
retries: 5
});
}
how can this be achieved?
or in other words, how can I call another function (function A) only after all retries attempts failed? and call function B if it didn't throw at all.
const retry = require('async-retry');
async function updateDB(updateUser) {
try{
const result = await retry(async () => {
const res = await Promise.all(updateUser).then(()=>{
try{
return new Promise((resolve) => resolve('OK')), { retries: 5 }
}catch(e){
return new Promise((resolve) => resolve('KO')), { retries: 5 };
}
});
}
);
}catch(err){
console.log('The function execution failed !')
}
}
you can use function onRetry, something like this
const retry = require('async-retry');
async function updateDB(updateUser) {
await retry(async () => {
const res = await test();
console.log('Success');
}, {
onRetry: (err, number) => {
console.log('attempt', number)
if (number === 5) {
console.log(err)
}
},
retries: 5
});
}
Have you tried something like:
const result = await retry(async () => {
const res = await updateUser;
if (/* some error after finishing all retries*/) {
console.log('failed');
}
console.log('Success');
return 'success';
}, {
retries: 5
});
if (result != 'success') {
console.log('all failed');
}

How to get async await / promise based response

So I have a code as below. There is a function that calls 2 axios requests to fetch some sample API data.
function fetch_records(){
var api_url1 = "https://api.github.com/users/mojombo"
var api_url2 = "https://api.github.com/users/defunkt"
axios.get(api_url1)
.then(function (response) {
console.log('Data1 received: ',response);
})
.catch(function (error) {
console.log(error);
})
axios.get(api_url2)
.then(function (response) {
console.log('Data2 received: ',response);
})
.catch(function (error) {
console.log(error);
})
}
And then I want to run this function fetch_records() as below
console.log('Script started');
fetch_records();
console.log('Script ended');
So that the output should be
Script started
... api response data ...
Script ended
But because Javascript is asynchronous, it always gives output as below
Script started
Script ended
... api response data ...
I belive async/await or promise is used to achieve the response I want but I am not sure how to use that exactly.
Just use async/await keywords, but remember JS always is JS.
async function fetch_records() { // a async function
var api_url1 = "https://api.github.com/users/mojombo"
var api_url2 = "https://api.github.com/users/defunkt"
// waterfall way
const data1 = await axios.get(api_url1); // await
console.log('Data1 received: ', data1);
const data2 = await axios.get(api_url2); // await
console.log('Data2 received: ', data2);
// parallel way
// const [data1, data2] = await Promise.all([
// axios.get(api_url1),
// axios.get(api_url2)
// ]);
// console.log(data1, data2);
}
(async () => {
try {
console.log('Script started');
await fetch_records(); // await a async function (Thenable object)
console.log('Script ended');
} catch(err) {
console.error(err);
}
})();
change your function to return promises:
function fetch_records() {
var api_url1 = "https://api.github.com/users/mojombo"
var api_url2 = "https://api.github.com/users/defunkt"
const promise1 = axios.get(api_url1)
.then(function (response) {
console.log('Data1 received: ',response);
})
.catch(function (error) {
console.log(error);
})
const promise2 = axios.get(api_url2)
.then(function (response) {
console.log('Data2 received: ',response);
})
.catch(function (error) {
console.log(error);
});
return [promise1, promise2];
}
now use promise.all :
Promise.all(fetch_records()).then(function(response) {
console.log(response[0], response[1]);
});
function fetch_records() {
var api_url1 = "https://api.github.com/users/mojombo"
var api_url2 = "https://api.github.com/users/defunkt"
return [
axios.get(api_url1),
axios.get(api_url2)
]
}
console.log('Script started');
Promise.all(fetch_records()).then(res => {
console.log(res);
console.log('Script ended');
})
Promise.all will wait till all promises are resolved, more about it
function fetch_records() {
var api_url1 = "https://api.github.com/users/mojombo";
return new Promise((resolve, reject) => {
axios
.get(api_url1)
.then(function(response) {
console.log("Data1 received: ", response);
resolve(response);
})
.catch(function(error) {
console.log(error);
reject(error);
});
});
}
Use with Async/Await :
async function getData() {
let data = await fetch_records();
console.log("Fetch Records :: ", data);
}

https requests in loop, call function after last request has been made node

Assuming I am calling https a multiple times to retrieve data, and I want to call a function formatJsonToLocale at the end of the last request. Is there a way to determine when that request has ended, other than checking for the last element of the array.
let sheetsArray = []
function sheetsAsJsonById (ids) {
for (let i = 0; i < ids.length; i++) {
const queryUrl = `sheets.html`
https
.get(queryUrl, res => {
let stream = []
res
.on('data', function (data) {
stream.push(data)
})
.on('end', function () {
let data = Buffer.concat(stream)
data = JSON.parse(data)
sheetArrays.push(data['values'])
formatJsonToLocale(sheetsArray) // <----- call this one after last request
})
})
.on('error', err => {
console.error(`Error in response: ${err}`)
})
}
}
when I call formatJsonToLocale outside of the function I will have the problem that the former function might not be finished as https handles stuff asynchronously.
Any suggestions on how to handle this?
You would need to keep track of execution of async code (https.get) that is getting executed within for loop. This can be achieved using promises as below:
let sheetsArray = []
function sheetsAsJsonById (ids) {
let promises = []
for (let i = 0; i < ids.length; i++) {
const queryUrl = `sheets.html`
promises.push(makeHTTPRequest(queryUrl))
}
Promise.all(promises).then((sheetArrays) => {
formatJsonToLocale(sheetsArray)
})
}
const makeHTTPRequest = (url) => {
return new Promise((resolve, reject) => {
https
.get(url, res => {
let stream = []
res
.on('data', function (data) {
stream.push(data)
})
.on('end', function () {
let data = Buffer.concat(stream)
data = JSON.parse(data)
resolve(data)
})
.on('error', err => {
console.error(`Error in response: ${err}`)
})
})
}
If you want to stick to callbacks you could use async.each function of async node module.
Wrap https.get in a Promise, which resolves on the end event, and rejects on any error. Now you can await the promise, and call the function once the for loop is done
let sheetsArray = []
function sheetsAsJsonById(ids) {
for (let i = 0; i < ids.length; i++) {
const queryUrl = `sheets.html`
await new Promise((resolve, reject) => {
https
.get(queryUrl, res => {
let stream = []
res
.on('data', function(data) {
stream.push(data)
})
.on('end', function() {
let data = Buffer.concat(stream)
data = JSON.parse(data)
sheetsArray.push(data['values'])
resolve();
})
})
.on('error', err => {
reject(err);
})
})
}
formatJsonToLocale(sheetsArray)
}

Categories