how to run multiple functions respectively while using promises? - node.js

I'm trying to run 4 functions in order one by one, I've tried the code below, but some how the function stuck after running the first and the second ones
code exampl:
const Bluebird = require('bluebird');
///// also tried changing all Bluebird below to Promise -> didn't work
//const Promise = require('bluebird');
const promisesFunc = async (array) => {
let interval = 1000;
const delayPromise1 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
const delayPromise2 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
const delayPromise3 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
const delayPromise4 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
try {
/////////////// first attempt //////////////
await Bluebird.map(array, (data, index) => delayPromise1(data, index * interval))
await Bluebird.map(array, (data, index) => delayPromise2(data, index * interval))
await Bluebird.map(array, (data, index) => delayPromise3(data, index * interval))
await Bluebird.map(array, (data, index) => delayPromise4(data, index * interval))
console.log('done ***************************************************');
setTimeout(() => {
console.log('response was sent');
res.status(200).json('done')
}, 1000);
/////////////// second attempt ////////////
const promises = Bluebird.map(array, (data, index) => delayPromise1(data, index * interval))
.then(() => Bluebird.map(array, (data, index) => delayPromise2(data, index * interval)))
.then(() => Bluebird.map(array, (data, index) => delayPromise3(data, index * interval)))
.then(() => Bluebird.map(array, (data, index) => delayPromise4(data, index * interval)))
.then(() => {
setTimeout(() => {
console.log('response was sent');
res.status(200).json('done')
}, 1000);
})
.catch(err => console.error(err))
await Promise.all([promises]);
///////////// third attempt ////////////////////
const promises1 = array.map((data, index) => delayPromise1(data, index * interval));
const promises2 = array.map((data, index) => delayPromise2(data, index * interval));
const promises3 = array.map((data, index) => delayPromise3(data, index * interval));
const promises4 = array.map((data, index) => delayPromise4(data, index * interval));
await Promise.all([promises1, promises2, promises3, promises4]);
setTimeout(function(){
console.log('response was sent');
res.status(200).json('done')
}, 1000);
} catch (e) {
console.error(e);
}
}
promisesFunc(array)
Note in first and second attempt delayPromise1 and delayPromise2 functions runs successfully but then stops and doesn't continue, other solutions it doesn't work respectively
any idea why this is happening and is there any better solution to promisify these functions to run respectively.
PS functions structure is needed to be like this. and they need to run in order one after the other respectively.
mapping in an array of data , then do some work on it inside delayPromise functions, then resolve(). resolve the promise doesn't have to wait for the code execution to finish in some cases.

Your third attempt is the way to go. But you could send your response when your Promise.all resolve and all async operations are done.
const promises1 = array.map((data, index) => delayPromise1(data, index * interval));
const promises2 = array.map((data, index) => delayPromise2(data, index * interval));
const promises3 = array.map((data, index) => delayPromise3(data, index * interval));
const promises4 = array.map((data, index) => delayPromise4(data, index * interval));
await Promise.all([promises1, promises2, promises3, promises4]).then(() => {
console.log('response was sent');
return res.status(200).json('done')
})

If you want to run parallel pass all delay functions pass inside Promise.all. If you want to run sequentially use like below.
const promisesFunc = async (array) => {
let interval = 1000;
const delayPromise1 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
const delayPromise2 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
const delayPromise3 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
const delayPromise4 = (data, delayDuration) => {
return new Promise((resolve) => {
setTimeout(() => {
/// do some code here requires .map function may take 10s or more
resolve();
}, delayDuration)
});
};
try {
console.log("START");
await Promise.all(array.map((data, index) => delayPromise1(data, index * interval)));
console.log("Done delayPromise1");
await Promise.all((array.map((data, index) => delayPromise2(data, index * interval))));
console.log("Done delayPromise2");
await Promise.all(array.map((data, index) => delayPromise3(data, index * interval)));
console.log("Done delayPromise3");
await Promise.all(array.map((data, index) => delayPromise4(data, index * interval)));
console.log("Done delayPromise4");
console.log("DONE");
} catch (e) {
console.error(e);
}
};
promisesFunc([1, 2, 3])

I would use the array .reduce method like so:
[delayPromise1, delayPromise2, ...]
.reduce((m, delayPromise) => {
/* here we chain the promises */
return Promise.resolve(m).then(delayPromise)
}, {/* any input data to be the argument of delayPromise1 */} )
.then( res => {
// do something when all is ready
})

Related

Returning the result after reading the csv file

I am using PapaParse to read remote csv file and return the result, but every time it's empty not sure why.
function importData(url){
const parseStream = Papa.parse(Papa.NODE_STREAM_INPUT, {});
let length = 0;
const dataStream = request
.get(url)
.pipe(parseStream);
let data: any[] = [];
parseStream.on("data", (chunk: any) => {
data.push(chunk);
});
dataStream.on("finish", (length) => {
console.log(data);//this returns data
console.log(data);//this returns data length
length = data.length;
return data;// Empty
});
return length;//Empty
}
The statement return length will be executed before the dataStream's finish-event has been emitted. If you want your importData function to wait until this happens, you can wrap the parsing in a promise and wait until it's been resolved (still needs error handling, but should give you a start):
function importData(url){
const parsePromise = new Promise((resolve, reject) => {
const parseStream = Papa.parse(Papa.NODE_STREAM_INPUT, {});
const dataStream = request
.get(url)
.pipe(parseStream);
let data: any[] = [];
parseStream.on("data", (chunk: any) => {
data.push(chunk);
});
dataStream.on("finish", () => {
resolve(data);
});
});
return parsePromise
.then((data) => {
console.log(data.length);
return data;
})
}
You can simplify this using async/await:
async function importData(url) {
const data = await new Promise((resolve, reject) => {
const parseStream = Papa.parse(Papa.NODE_STREAM_INPUT, {});
const dataStream = request
.get(url)
.pipe(parseStream);
const data: any[] = [];
parseStream.on("data", (chunk: any) => {
data.push(chunk);
});
dataStream.on("finish", () => {
resolve(data);
});
});
console.log(data.length);
return data;
}

How can you trigger a throw instruction after a certain time?

Problem: A library function is called, which sometimes does not work. If this function does not work, it sometimes happens that it does not return an error message but is stuck in an infinite loop.
Idea: My idea now would have been to use a timer, which executes a throw instruction after a given time, if the function has not been completed successfully before.
If the function was successfully completed, before the end of the timer, the timer should simply be closed.
Not working example code:
var errorCounter = 0;
async function a(m) {
try {
var myVar = setTimeout(function () {
throw console.log('Error');
}, 60000);
await libraryFunction(m);
clearTimeout(myVar);
} catch {
errorCounter++;
console.log(errorCounter);
}
}
You could use Promise.race to simulate a timeout (play with the numerical values below):
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('timeout')), 1000);
});
const task = new Promise((resolve, _) => {
setTimeout(() => resolve('done'), 2000);
});
Promise.race([timeout, task])
.then((result) => { console.log(result); })
.catch((err) => { console.log(err.message); });
So in your case, it would look something like this:
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('timeout')), 60 * 1000);
});
var errorCounter = 0;
function a(m) {
Promise.race([timeout, libraryFunction(m)])
.then((res) => { console.log(res); })
.catch((err) => {
errorCounter++;
console.log(errorCounter);
});
}
You can use Promise.race for this type of thing:
const MAX_WAIT_TIME = 500
const libFn = new Promise((resolve, reject) => {
setTimeout(() => resolve('success'), Math.random() * 1000);
})
const throwFn = new Promise((resolve, reject) => {
setTimeout(() => reject('failure'), MAX_WAIT_TIME);
})
;(async () => {
const result = await Promise.race([libFn, throwFn])
console.log('done') // this line won't execute if the timeout is reached
})()

Coinbase API large responses and slow

The following code takes a good 5 to 10 seconds to resolve (there are 5 API-calls). It's not usable as it is. Is the slow response my fault or is the Coinbase API just slow and large?
app.get('/buys', async (req, res) => {
const buys = await getAllBuys()
res.json(buys)
})
const fetchAllAccounts = () => {
return new Promise(
(resolve, reject) => {
coinbase.getAccounts(null, (err, accounts) => {
if (err) {
reject(err)
}
else{
resolve(accounts)
}
})
}
)
}
const fetchAllBuys = (account) => {
return new Promise(
(resolve, reject) => {
account.getBuys(null, (err, buys) => {
if (err) {
reject(err)
}
else{
resolve(buys)
}
})
}
)
}
const getAllBuys = async () => {
const accounts = await fetchAllAccounts()
let combinedBuys = []
for (let account of accounts) {
const buys = await fetchAllBuys(account)
combinedBuys = [...combinedBuys, ...buys]
}
//console.log(combinedBuys)
return combinedBuys
}
Response is a array with items that include account information like certificates and so on.
Ok, so it was my code. I the code above I wait for each request to finish before firing off a new one. Which results in unnecessary delay. With the Promise.all method we can generate all the promises and resolve them at the same time. Look at the refactored code bellow.
app.get('/buys', async (req, res) => {
console.time('[/buys]');
const promises = await getAllBuys()
const buys = await Promise.all(promises)
res.json(buys)
console.timeEnd('[/buys]');
})
const fetchAllAccounts = () => {
return new Promise(
(resolve, reject) => {
coinbase.getAccounts(null, (err, accounts) => {
if (err) {
reject(err)
}
else{
resolve(accounts)
}
})
}
)
}
const fetchAllBuys = (account) => {
return new Promise(
(resolve, reject) => {
account.getBuys(null, (err, buys) => {
if (err) {
reject(err)
}
else{
resolve(buys)
}
})
}
)
}
const getAllBuys = async () => {
const accounts = await fetchAllAccounts()
let promises = []
for (let account of accounts) {
promises.push(fetchAllBuys(account))
}
return promises
}
From 2,5 / 3 seconds to 0,8 / 1 second.

Async Await Node js

I am learning async await using node js
var testasync = async () =>
{
const result1 = await returnone();
return result1;
}
testasync().then((name)=>{
console.log(name);
}).catch((e) =>{
console.log(e);
});
var returnone = () =>{
return new Promise((resolve,reject)=>
{
setTimeout(()=>{
resolve('1');
},2000)
})
}
It fails with returnone is not a function. What am i doing wrong? calling the function just by itself work
returnone().then((name1) => {
console.log(name1)
})
Just calling the above code works
The reason you are getting this error because of hoisting. Your code seen by JS would look like this
var returnone;
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
returnone = () => {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
So the value of returnone is undefined.
You are assigning the function to the variable returnone at the end of the code, but you are trying to call that function before this assignment. You have two options to fix the code:
Option 1
Use a function declaration; this way, the function is hoisted and you can use it right from the start:
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
function returnone() {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
Option 2
Assign the function to the variable before you try to call it:
var returnone = () => {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});

promise chaining when splitting the chain

In the following code
var p = new Promise((resolve, reject) => {
console.log('a');
resolve();
});
p.then(() => {
console.log('b');
}).then(() => {
console.log('c');
});
p.then(() => {
console.log('z');
})
I expect the console output to be:
a
b
c
z
Instead I got:
a
b
z
c
but with this code I got the expected result
var p = new Promise((resolve, reject) => {
console.log('a');
resolve();
}).then(() => {
console.log('b');
}).then(() => {
console.log('c');
});
p.then(() => {
console.log('z');
})
Can anyone explain the way promise chaining is done in this case?
Each then returns you new Promise which depends of callback resolution.
That's difference.
var p = new Promise((resolve, reject) => {
console.log('a');
resolve();
});
var a = p.then(() => {
console.log('b');
});
a.then(() => {
console.log('c');
});
p.then(() => {
console.log('z');
});
Timeline:
initial resolve // a
p resolved // b, z independently
a resolved // c
In second case your p points to promise returned by last then:
var a = new Promise(foo('a'));
var b = a.then(foo('b'));
var p = b.then(foo('c'));
p.then(foo('z'));
You should not to rely on one level resolving order. Because this happens eventually and order is realy undefined(depend on internal implementation).

Resources