Node.Js loop inside post request [duplicate] - node.js

I have a loop which calls a method that does stuff asynchronously. This loop can call the method many times. After this loop, I have another loop that needs to be executed only when all the asynchronous stuff is done.
So this illustrates what I want:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
I'm not very familiar with promises, so could anyone help me to achieve this?
This is how my doSomeAsyncStuff() behaves:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Maybe I have to do something like this:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
But I'm not sure of the syntax.

You can use Promise.all (spec, MDN) for that: It accepts a bunch of individual promises and gives you back a single promise that is resolved when all of the ones you gave it are resolved, or rejected when any of them is rejected.
So if you make doSomeAsyncStuff return a promise, then:
const promises = [];
// ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− use `const` or `let`, not `var`
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−−−−−−−−−− added missing declaration
promises.push(doSomeAsyncStuff());
}
Promise.all(promises)
.then(() => {
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−− added missing declaration
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
})
.catch((e) => {
// handle errors here
});
MDN has an article on promises here. I also cover promsies in detail in Chapter 8 of my book JavaScript: The New Toys, links in my profile if you're interested.
Here's an example:
function doSomethingAsync(value) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Resolving " + value);
resolve(value);
}, Math.floor(Math.random() * 1000));
});
}
function test() {
const promises = [];
for (let i = 0; i < 5; ++i) {
promises.push(doSomethingAsync(i));
}
Promise.all(promises)
.then((results) => {
console.log("All done", results);
})
.catch((e) => {
// Handle errors here
});
}
test();
Sample output (because of the Math.random, what finishes first may vary):
Resolving 3
Resolving 2
Resolving 1
Resolving 4
Resolving 0
All done [0,1,2,3,4]

A reusable function works nicely for this pattern:
function awaitAll(count, asyncFn) {
const promises = [];
for (i = 0; i < count; ++i) {
promises.push(asyncFn());
}
return Promise.all(promises);
}
OP example:
awaitAll(5, doSomeAsyncStuff)
.then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
.catch(e => console.error(e));
A related pattern, is iterating over an array and performing an async operation on each item:
function awaitAll(list, asyncFn) {
const promises = [];
list.forEach(x => {
promises.push(asyncFn(x));
});
return Promise.all(promises);
}
Example:
const books = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }];
function doSomeAsyncStuffWith(book) {
return Promise.resolve(book.name);
}
awaitAll(books, doSomeAsyncStuffWith)
.then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
.catch(e => console.error(e));

/*** Worst way ***/
for(i=0;i<10000;i++){
let data = await axios.get(
"https://yourwebsite.com/get_my_data/"
)
//do the statements and operations
//that are dependant on data
}
//Your final statements and operations
//That will be performed when the loop ends
//=> this approach will perform very slow as all the api call
// will happen in series
/*** One of the Best way ***/
const yourAsyncFunction = async (anyParams) => {
let data = await axios.get(
"https://yourwebsite.com/get_my_data/"
)
//all you statements and operations here
//that are dependant on data
}
var promises = []
for(i=0;i<10000;i++){
promises.push(yourAsyncFunction(i))
}
await Promise.all(promises)
//Your final statement / operations
//that will run once the loop ends
//=> this approach will perform very fast as all the api call
// will happen in parallal

const doSomeAsyncStuff = async (funcs) => {
const allPromises = funcs.map(func => func());
return await Promise.all(allPromises);
}
doSomeAsyncStuff([
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
]);

Here is code that I wrote for myself in order to understand the answers stated here. I have mongoose queries in a for loop, so I put here the asyncFunction to take its place. Hope it helps anyone. You can run this script in node or any of many Javascript runtimes.
let asyncFunction = function(value, callback)
{
setTimeout(function(){console.log(value); callback();}, 1000);
}
// a sample function run without promises
asyncFunction(10,
function()
{
console.log("I'm back 10");
}
);
//here we use promises
let promisesArray = [];
let p = new Promise(function(resolve)
{
asyncFunction(20,
function()
{
console.log("I'm back 20");
resolve(20);
}
);
});
promisesArray.push(p);
for(let i = 30; i < 80; i += 10)
{
let p = new Promise(function(resolve)
{
asyncFunction(i,
function()
{
console.log("I'm back " + i);
resolve(i);
}
);
});
promisesArray.push(p);
}
// We use Promise.all to execute code after all promises are done.
Promise.all(promisesArray).then(
function()
{
console.log("all promises resolved!");
}
)

Here's an elegant solution for you if you want to do the same thing multiple times:
await Promise.all(new Array(10).fill(0).map(() => asyncFn()));
This creates an array with 10 items, fills it with zeros and then maps it to an array of promises.

Related

How to update an array of object using findById with loop or updateMany? [duplicate]

I have a loop which calls a method that does stuff asynchronously. This loop can call the method many times. After this loop, I have another loop that needs to be executed only when all the asynchronous stuff is done.
So this illustrates what I want:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
I'm not very familiar with promises, so could anyone help me to achieve this?
This is how my doSomeAsyncStuff() behaves:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Maybe I have to do something like this:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
But I'm not sure of the syntax.
You can use Promise.all (spec, MDN) for that: It accepts a bunch of individual promises and gives you back a single promise that is resolved when all of the ones you gave it are resolved, or rejected when any of them is rejected.
So if you make doSomeAsyncStuff return a promise, then:
const promises = [];
// ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− use `const` or `let`, not `var`
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−−−−−−−−−− added missing declaration
promises.push(doSomeAsyncStuff());
}
Promise.all(promises)
.then(() => {
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−− added missing declaration
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
})
.catch((e) => {
// handle errors here
});
MDN has an article on promises here. I also cover promsies in detail in Chapter 8 of my book JavaScript: The New Toys, links in my profile if you're interested.
Here's an example:
function doSomethingAsync(value) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Resolving " + value);
resolve(value);
}, Math.floor(Math.random() * 1000));
});
}
function test() {
const promises = [];
for (let i = 0; i < 5; ++i) {
promises.push(doSomethingAsync(i));
}
Promise.all(promises)
.then((results) => {
console.log("All done", results);
})
.catch((e) => {
// Handle errors here
});
}
test();
Sample output (because of the Math.random, what finishes first may vary):
Resolving 3
Resolving 2
Resolving 1
Resolving 4
Resolving 0
All done [0,1,2,3,4]
A reusable function works nicely for this pattern:
function awaitAll(count, asyncFn) {
const promises = [];
for (i = 0; i < count; ++i) {
promises.push(asyncFn());
}
return Promise.all(promises);
}
OP example:
awaitAll(5, doSomeAsyncStuff)
.then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
.catch(e => console.error(e));
A related pattern, is iterating over an array and performing an async operation on each item:
function awaitAll(list, asyncFn) {
const promises = [];
list.forEach(x => {
promises.push(asyncFn(x));
});
return Promise.all(promises);
}
Example:
const books = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }];
function doSomeAsyncStuffWith(book) {
return Promise.resolve(book.name);
}
awaitAll(books, doSomeAsyncStuffWith)
.then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
.catch(e => console.error(e));
/*** Worst way ***/
for(i=0;i<10000;i++){
let data = await axios.get(
"https://yourwebsite.com/get_my_data/"
)
//do the statements and operations
//that are dependant on data
}
//Your final statements and operations
//That will be performed when the loop ends
//=> this approach will perform very slow as all the api call
// will happen in series
/*** One of the Best way ***/
const yourAsyncFunction = async (anyParams) => {
let data = await axios.get(
"https://yourwebsite.com/get_my_data/"
)
//all you statements and operations here
//that are dependant on data
}
var promises = []
for(i=0;i<10000;i++){
promises.push(yourAsyncFunction(i))
}
await Promise.all(promises)
//Your final statement / operations
//that will run once the loop ends
//=> this approach will perform very fast as all the api call
// will happen in parallal
const doSomeAsyncStuff = async (funcs) => {
const allPromises = funcs.map(func => func());
return await Promise.all(allPromises);
}
doSomeAsyncStuff([
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
]);
Here is code that I wrote for myself in order to understand the answers stated here. I have mongoose queries in a for loop, so I put here the asyncFunction to take its place. Hope it helps anyone. You can run this script in node or any of many Javascript runtimes.
let asyncFunction = function(value, callback)
{
setTimeout(function(){console.log(value); callback();}, 1000);
}
// a sample function run without promises
asyncFunction(10,
function()
{
console.log("I'm back 10");
}
);
//here we use promises
let promisesArray = [];
let p = new Promise(function(resolve)
{
asyncFunction(20,
function()
{
console.log("I'm back 20");
resolve(20);
}
);
});
promisesArray.push(p);
for(let i = 30; i < 80; i += 10)
{
let p = new Promise(function(resolve)
{
asyncFunction(i,
function()
{
console.log("I'm back " + i);
resolve(i);
}
);
});
promisesArray.push(p);
}
// We use Promise.all to execute code after all promises are done.
Promise.all(promisesArray).then(
function()
{
console.log("all promises resolved!");
}
)
Here's an elegant solution for you if you want to do the same thing multiple times:
await Promise.all(new Array(10).fill(0).map(() => asyncFn()));
This creates an array with 10 items, fills it with zeros and then maps it to an array of promises.

Async Await not waiting for image upload to Azure blob to complete [duplicate]

I have a loop which calls a method that does stuff asynchronously. This loop can call the method many times. After this loop, I have another loop that needs to be executed only when all the asynchronous stuff is done.
So this illustrates what I want:
for (i = 0; i < 5; i++) {
doSomeAsyncStuff();
}
for (i = 0; i < 5; i++) {
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
I'm not very familiar with promises, so could anyone help me to achieve this?
This is how my doSomeAsyncStuff() behaves:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
editor.on('instanceReady', function(evt) {
doSomeStuff();
// There should be the resolve() of the promises I think.
})
}
Maybe I have to do something like this:
function doSomeAsyncStuff() {
var editor = generateCKEditor();
return new Promise(function(resolve,refuse) {
editor.on('instanceReady', function(evt) {
doSomeStuff();
resolve(true);
});
});
}
But I'm not sure of the syntax.
You can use Promise.all (spec, MDN) for that: It accepts a bunch of individual promises and gives you back a single promise that is resolved when all of the ones you gave it are resolved, or rejected when any of them is rejected.
So if you make doSomeAsyncStuff return a promise, then:
const promises = [];
// ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− use `const` or `let`, not `var`
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−−−−−−−−−− added missing declaration
promises.push(doSomeAsyncStuff());
}
Promise.all(promises)
.then(() => {
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−− added missing declaration
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
})
.catch((e) => {
// handle errors here
});
MDN has an article on promises here. I also cover promsies in detail in Chapter 8 of my book JavaScript: The New Toys, links in my profile if you're interested.
Here's an example:
function doSomethingAsync(value) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Resolving " + value);
resolve(value);
}, Math.floor(Math.random() * 1000));
});
}
function test() {
const promises = [];
for (let i = 0; i < 5; ++i) {
promises.push(doSomethingAsync(i));
}
Promise.all(promises)
.then((results) => {
console.log("All done", results);
})
.catch((e) => {
// Handle errors here
});
}
test();
Sample output (because of the Math.random, what finishes first may vary):
Resolving 3
Resolving 2
Resolving 1
Resolving 4
Resolving 0
All done [0,1,2,3,4]
A reusable function works nicely for this pattern:
function awaitAll(count, asyncFn) {
const promises = [];
for (i = 0; i < count; ++i) {
promises.push(asyncFn());
}
return Promise.all(promises);
}
OP example:
awaitAll(5, doSomeAsyncStuff)
.then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
.catch(e => console.error(e));
A related pattern, is iterating over an array and performing an async operation on each item:
function awaitAll(list, asyncFn) {
const promises = [];
list.forEach(x => {
promises.push(asyncFn(x));
});
return Promise.all(promises);
}
Example:
const books = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }];
function doSomeAsyncStuffWith(book) {
return Promise.resolve(book.name);
}
awaitAll(books, doSomeAsyncStuffWith)
.then(results => console.log('doSomeStuffOnlyWhenTheAsyncStuffIsFinished', results))
.catch(e => console.error(e));
/*** Worst way ***/
for(i=0;i<10000;i++){
let data = await axios.get(
"https://yourwebsite.com/get_my_data/"
)
//do the statements and operations
//that are dependant on data
}
//Your final statements and operations
//That will be performed when the loop ends
//=> this approach will perform very slow as all the api call
// will happen in series
/*** One of the Best way ***/
const yourAsyncFunction = async (anyParams) => {
let data = await axios.get(
"https://yourwebsite.com/get_my_data/"
)
//all you statements and operations here
//that are dependant on data
}
var promises = []
for(i=0;i<10000;i++){
promises.push(yourAsyncFunction(i))
}
await Promise.all(promises)
//Your final statement / operations
//that will run once the loop ends
//=> this approach will perform very fast as all the api call
// will happen in parallal
const doSomeAsyncStuff = async (funcs) => {
const allPromises = funcs.map(func => func());
return await Promise.all(allPromises);
}
doSomeAsyncStuff([
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
() => new Promise(resolve => setTimeout(() => resolve(), 100)),
]);
Here is code that I wrote for myself in order to understand the answers stated here. I have mongoose queries in a for loop, so I put here the asyncFunction to take its place. Hope it helps anyone. You can run this script in node or any of many Javascript runtimes.
let asyncFunction = function(value, callback)
{
setTimeout(function(){console.log(value); callback();}, 1000);
}
// a sample function run without promises
asyncFunction(10,
function()
{
console.log("I'm back 10");
}
);
//here we use promises
let promisesArray = [];
let p = new Promise(function(resolve)
{
asyncFunction(20,
function()
{
console.log("I'm back 20");
resolve(20);
}
);
});
promisesArray.push(p);
for(let i = 30; i < 80; i += 10)
{
let p = new Promise(function(resolve)
{
asyncFunction(i,
function()
{
console.log("I'm back " + i);
resolve(i);
}
);
});
promisesArray.push(p);
}
// We use Promise.all to execute code after all promises are done.
Promise.all(promisesArray).then(
function()
{
console.log("all promises resolved!");
}
)
Here's an elegant solution for you if you want to do the same thing multiple times:
await Promise.all(new Array(10).fill(0).map(() => asyncFn()));
This creates an array with 10 items, fills it with zeros and then maps it to an array of promises.

How to add timeout to this async function

I want to add a timeout such that if any of these "tasks" takes longer than 5 minutes, it should stop that function and resolve the promise. I've been struggling a bit, any help is appreciated. Thanks!
if (require.main === module) {
(async () => {
const tasks = [];
for (let i = 1; i <= NB_PARALLEL; i++) {
tasks.push(buildReferenceSpaceCollection(json));
}
const results = await Promise.all(tasks);
console.log(results);
process.exit(0);
})().catch(console.error);
}
You could define a wait-function that rejects after the given amount of time and then use Promise.race on that wait-function and your Promise.all. Now, if your promises inside Promise.all take longer than the wait, Promise.race will reject, otherwise the resolved values will be assigned to results.
function wait(ms) {
return new Promise((_, reject) => {
setTimeout(() => {
reject(new Error("wait time exceeded"));
}, ms);
})
}
(async () => {
const tasks = [];
for (let i = 1; i <= NB_PARALLEL; i++) {
tasks.push(buildReferenceSpaceCollection(json));
}
// 5 mins in ms
const wait5MinPromise = wait(5*60*1000);
const results = await Promise.race([wait5MinPromise, Promise.all(tasks)]);
console.log(results);
process.exit(0);
})().catch(console.error)
;
Just for fun (Live demo):
import { CPromise } from "c-promise2";
const generateYourAsyncTaskHereToAddInQueue= async (value)=> {
console.log(`Inner task started [${value}]`);
await CPromise.delay(1000);
return value;
}
(async () => {
const results = await CPromise.all(function* () {
for (let i = 0; i < 10; i++) {
yield generateYourAsyncTaskHereToAddInQueue(`Task result ${i}`);
}
}, {concurrency: 3}).timeout(5000);
console.log(`results:`, results);
return results;
})().catch(console.error);

delay in between chain of promises

everyone, I have been trying out a delay of 8secs within the chain of promises i.e promise.all.
But unfortunately, it's not executing the way I want it to execute it.
I want a delay of 8secs between an array of promises and I have tried out some code. Anyone any idea how to put it or where I am going wrong?
var cron = require('node-cron');
let cron_schedule="* * * * *";
let max_Request = 10,requestProcess = [];
let checkCronJob = () => {
while (max_Request > 0){
requestProcess.push(processRequest(produce))
requestProcess.push(delay(8000));
}
return Promise.all(requestProcess).then((result) => {
console.log(result);
});
}
var delay = function () {
var promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(true)
}, 8000);
});
return promise;
}
let processRequest = async (produce) => {
max_Request--;
return await Promise.resolve(true);
}
checkCronJob();
"processRequest" will return a promise and after that, I added a delay of 8secs but it is actually executing all the promises in one go after a delay of 8secs.
I wanted the promises to execute within the delay of 8secs.
For what you want to do:
var delay = promise => {
return new Promise((resolve, reject) => {
promise.then(() => {
setTimeout(() => {
resolve(true)
}, 8000);
});
});
}
var recursiveDelay = n => {
delay(processRequest(produce)).then(() => { if(n > 0) recursiveDelay(n-1)});
}
recursiveDelay(10);
Promises are executed immediately, if you want to ensure a delay before starting the next action then you can't setup the promises like you are.
You would need to do something like:
while (max_Request > 0) {
await processRequest(produce);
await delay(8000);
max_Request--;
}
If you can't use async / await, then it's slightly uglier
let req;
while (max_Request > 0) {
if (!req) {
req = processRequest(produce);
} else {
req.then(processRequest(produce));
}
req.then(delay(8000));
max_Request--;
}
return req.then(console.log);

How can I use 'finally' within a 'Promise' clause in NodeJS?

I want something like this:
let promises = [];
for (let i = 0; i < some_length; i++) {
let output = '';
promises.push(some_func(i)
.then((result) => {
output = result;
})
.catch((error) => {
output = error.message;
})
.finally(() => {
console.log(output);
})
);
}
return Promise.all(promises);
But I get a runtime error .then(...).catch(...).finally is not a function.
How can I resolve this?
Node 10 finally added support for it. Tested with node 10.7.0.
Promise.resolve().finally(() => {
console.log("It finally works!")
})
It finally works!
(Chrome and Firefox also support it btw.)
Actually, I Think your some-func function isn't return Promise, with returning JavaScript Promisees the then, catch and finally has meaning, so I think you must declare some_func function as a new instance of Promise object, see below code:
let promises = [];
for (let i = 0; i < some_length; i++) {
let output = '';
let some_func = (i) => {
return new Promise(function(resolve, reject) {
setTimeout(resolve(`success: ${i}`), 100, 'foo');
});
}
promises.push(some_func(i)
.then((result) => {
output = result;
})
.catch((error) => {
output = error.message;
})
.finally(() => {
console.log(output);
})
);
}
return Promise.all(promises);
Maybe this code have some other errors, I don't know because I do not test it, but undoubtedly your error is for just like I said in above sentences.

Resources