JavaScript - replace setTimeout with async / await - javascript

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"
);
});
}

Related

Second function not called asynchronously in nodejs

I am trying to call some function using a single express router , I want to call them in order, meaning that I don't want getLaps() function to execute before get streams function has done all the work , so I tried to use some solutions I found on the internet but it didn't work, the second function doesn't execute. Please help.
Here is my code :
router.get("/", async (req, res,done) => {
res.status(201).send('created user')
return getLaps(function () {
getStreams(function () {
});
});
// await getStreams();
// await getLaps();
// console.log("hey")
});
Here is the get laps function :
function getLaps(req) {
const access_token = '75f2d92fdc445033312854d775e039b6c5bf04e7';
//for test 3756582581,
const idL = [5567017025, 5566531480];
const stravaClient = StravaClientService.getClient(access_token);
const activityService = StravaActivityService(stravaClient);
var params = {
TableName: "run-id",
Key: {
"id": "15428785",
}
};
console.log("cool laps")
docClient.get(params, async function (err, data) {
if (err) {
console.log("Error", err);
} else {
}
idL.map((id, index) => setTimeout(() => activityService.listLaps(id), (5 + index) * 60)
)
//data.Item.json
});
}
and the streams function :
function getStreams(req) {
const idS = [
5567017025, 5566531480
];
const stravaClient = StravaClientService.getClient(access_token);
const activityService = StravaActivityService(stravaClient);
var params = {
TableName: "run-id",
Key: {
"id": "15428785",
}
};
console.log("cool streams")
docClient.get(params, async function (err, data) {
if (err) {
console.log("Error", err);
} else {
idS.map((id, index) => setTimeout(() => activityService.streamActivity(id), (5 + index) * 60))
console.log("got the streams")
}
});
}
in your getStream and getLaps function return promises instead of other object/Stuff like
async function getStream(){
return new Promise(async (resolve, reject){
//Do something
//where you want to return something just call resolve function like
resolve()
//if you want some output of getStream() just pass it to resolve function
//const result = 'I'm result'
resolve(result)
})
}
do same thing with the laps function and in your router call them with await keyword

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');
}

Run a function after a loop

I would like to run a function after the for loop done looping, but in my case the function after the for loop runs before the loop even finished.
Here's my code
let orderedItems = [];
for (let i = 0; i < orderCode.length; i++) {
menuModel.findOne({
_id: orderCode[i]
}, (err, order) => {
if (order) {
orderedItems.push(order.name);
}
});
}
console.log(orderedItems); // all the tasks below run before the loop finished looping
let orderData = new orderModel();
orderData._id = helpers.createRandomString(5).toUpperCase();
orderData.username = username;
orderData.orderCode = orderCode;
orderData.orderedItems = orderedItems;
orderData.totalPrice = 5;
orderData.save((err) => {
if (err) {
console.log(err);
callback(500, {
'Error': '1'
});
}
callback(200, {
'Message': 'Successfully ordered'
});
});
as #RishikeshDhokare said everything is executed asynchronously. so the trick is to split the tasks into separate functions.
so first we execute an async function you can use promises or async await
then we say after all the async tasks have been completed do the save task.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
const orderCode = [1, 2, 3]
const menuModel = {
findOne: item => new Promise(resolve => resolve({
_id: item._id,
name: 'name'
}))
}
class orderModel {
save(cb) {
return cb(null)
}
}
/*
ignore all above here i'm mocking your funcs
and vars so that the code works
*/
let orderedItems = [];
function getAllOrderedItems() {
const promises = orderCode.map(id => {
return menuModel.findOne({
_id: id
});
})
console.log('...start the request')
// fire all async items then resolve them all at once
return Promise.all(promises)
.then((data) => {
console.log('...finished all requests')
return orderedItems.concat(data);
})
.catch(err => console.log(err))
}
function handleSave(data) {
let orderData = new orderModel();
console.log(data)
console.log('...start save')
orderData.save((err) => {
console.log('...save finished')
});
}
//do all the async tasks then do the save task
getAllOrderedItems()
.then((data) => handleSave(data))

Un-nest JavaScript Firestore Functions

How can I rewrite this code to not be nested in itself? I also need access to the values obtained in the previous functions calls.
return docRef2.doc(`/users_stripe/${context.params.userID}`).get()
.then(snapshot => {
console.log("augu", snapshot);
return stripe.customers.createSource( jsonParser(snapshot._fieldsProto.id, "stringValue"),
{ source: jsonParser(snap._fieldsProto.token, "stringValue") },
function(err, card) {
console.log("listen people", card);
return docRef2.doc(`/users_stripe/${context.params.userID}/ptypes/ptypes`)
.set(card);
});
})
I am not sure what your code is doing here. I tried to write a pseudo/sample code that might give you an idea.
My code is not checked, so might contain problem.
let fun1 = () => {
return new Promise((resolve, reject) => {
docRef2.doc('/route').get().then(snapshot => {
if( snapshot ) resolve(snapshot);
else reject(snapshot);
})
})
}
let fun2 = (snapshot) => {
return new Promies((resolve, reject)=>{
stripe.customers.createSource(jsonParser(snapshot._fieldsProto.id, "stringValue"),
{ source: jsonParser(snap._fieldsProto.token, "stringValue") },
function (err, card) {
if (err) reject(false);// or whatever you wanna return
else resolve(card);
});
})
}
async function fun(){
let res1 = await fun1(); // Should contain snapshot
let res2 = await fun2(res1); // Should contain card
return docRef2.doc(`/users_stripe/${context.params.userID}/ptypes/ptypes`)
.set(card);
}

How to properly return value in async function when there are lot of callbacks

I have an async function, that calls other async functions, and when they are all done, I'm returning the results.
I don't wanna use Promise.all, because in case any of these functions fail, I just don't add them to my results.
ATM my code looks like this. It works, but I don't like the new Promise, I wanna do it in ES6 async way, so the callAll function should look like const callAll = async (query) => {
const callAll = (query) => {
return new Promise((resolve, reject) => {
const results = [];
const jobs = [
{
promise: someModuleFirst.search(query),
done: false
},
{
promise: someModuleSecond.search(query),
done: false
},
{
promise: someModuleThird.search(query),
done: false
}
];
const areAllDone = () => {
if(!jobs.filter((job) => !job.done).length) {
return true;
}
};
jobs.forEach((job) => {
job.promise.then((result) => {
job.done = true;
results.push(result);
if(areAllDone()) {
resolve(results);
}
}).catch((error) => {
job.done = true;
if(areAllDone()) {
resolve(results);
}
});
});
});
};
You could probably reduce your code to the following. You can return false from the catch handler, then filter out the data, which won't get passed into the result set.
const callAll = async (query) => {
const modules = [someModuleFirst, someModuleSecond, someModuleThird];
const jobs = modules.map((module) => module.search(query).catch(() => false);
const results = await Promise.all(jobs);
return results.filter(Boolean);
};
You can use Promise.all the only thing you need to do is to cache rejection and turn it into resolve.
function someAsyncFunction() {
return new Promise((resolve, reject) => {
setTimeout(function () {
if (Math.round(Math.random() * 100) % 2) {
return resolve('some result');
}
reject('some rejection');
})
}, 1);
}
var promises = [];
for (var i = 0; i < 10; i++) {
// this is important part
// catch block returns a promise with is resolved
// so all promises now will resolve
promises.push(someAsyncFunction().catch(function (reason) {
return reason;
}));
}
Promise.all(promises).then(function (results) {
console.log('All resolved');
console.log(results);
}).catch(function (reason) {
console.error('Rejected');
console.log(reason);
});
So in your case you need to change someModuleFirst.search(query) into some thing like this someModuleFirst.search(query).catch(e => e)

Categories