I need help with debugging this code/or learn efficient way to do it- I tried using bluebird.each to capture all executions within my forEach, but didn't get it work. Same with setting up a new promise with pure javascript. I need help how to execute my forEach FIRST and move on.
let arr = [];
let fields = ['environment', 'habitat', 'earth]
Promise.each(fields, field => {
nano.db.use(field).view('options', 'options')
.spread((body, header) => {
arr.push(body.rows);
})
}).then(() => console.log(arr))
Expected outcome:
arr to console.log ====> [1,2,3,4,5]
Actual outcome:
arr is an empty array ====> [ ]
I see it's a problem with asynchronicity, but I can't seem to figure out how to actually make this work. any input or resources will be greatly appreciated!
I haven't actually ran your code so sorry if I'm incorrect, but from looking at it and the bluebird docs I assume the correction you need to make is return your nano.db call wrapped in a promise inside the Promise.each
let arr = [];
let fields = ['environment', 'habitat', 'earth']
Promise.each(fields, field => {
return new Promise ((resolve, reject) => {
nano.db.use(field).view('options', 'options')
.spread((body, header) => {
arr.push(body.rows);
resolve();
})
});
}).then(() => console.log(arr))
I believe your assumption is right that you're having a problem with asynchronicity when getting an empty array back instead of what you expect. I'm assuming the .then method is firing before the nano.db gets back with the data.
I wrapped your call of nano.db in a promise so that it will await nano.db finishing since Promise.each supports returning promises inside it.
Bluebird's promise docs state with Promise.each.
If the iterator function returns a promise or a thenable, then the
result of the promise is awaited before continuing with next
iteration.
So, if a promise is not returned in your Promise.each and anything that is asynchronous happens inside then just as with a then or a catch method on a promise under the same circumstances.
As I do not know bluebird there may be a way to change that promise to be more bluebird like. The promise I wrapped around the nano.db call is just a normal es6 promise which bluebird may or may not have a different api for creating promises.
Related
I am looking for a answer on what to use in my nodeJS app.
I have code which handles my generic dB access to mssql. This code is written using an async functions and then I used a promise to call that function and all works fine.
As my app is getting bigger and code larger I am planning to move some of the logic into functions and then call them.
So my question is: is there a drawback to using a mix of async/await and promises or does it really not matter?
Async / await makes it easier to write more readable code as I have to read and write to multiple db’s before I return something and I need results of some of these.
So the question is what is the better approach?
Async / await on dB layer that’s set and can’t change
The logic layer async / await which would allow me a async / and await on the function call or if I go with promise for logic then I am stuck with promise on function call.
So I hope someone can give me more insight if one has more advantages than the other, besides being able to write cleaner code.
async/await and promises are closely related. async functions return promises, and await is syntactic sugar for waiting for a promise to be resolved.
The only drawback from having a mix of promises and async functions might be readability and maintainability of the code, but you can certainly use the return value of async functions as promises as well as await for regular functions that return a promise.
Whether you choose one vs the other mostly depends on availability (does your node.js / browser support async?) and on your aesthetic preference, but a good rule of thumb (based on my own preference at the time of writing) could be:
If you need to run asynchronous code in series: consider using async/await:
return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);
If you need nested promises: use async/await:
return asyncFunction()
.then(result => {
return f1(result)
.then(result2 => f2(result, result2);
})
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);
If you need to run it in parallel: use promises.
return Promise.all(arrayOfIDs.map(id => asyncFn(id)))
It has been suggested you can use await within an expression to await multiple tasks like so:
*note, this still awaits in sequence from left to right, which is OK if you don't expect errors. Otherwise the behaviour is different due to fail fast behaviour of Promise.all()
const [r1, r2, r3] = [await task1, await task2, await task3];
(async function() {
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Create Promises');
const task1 = t1(100);
const task2 = t1(200);
const task3 = t1(10);
console.log('Await for each task');
const [r1, r2, r3] = [await task1, await task2, await task3];
console.log('Done');
}())
But as with Promise.all, the parallel promises need to be properly handled in case of an error. You can read more about that here.
Be careful not to confuse the previous code with the following:
let [r1, r2] = [await t1(100), await t2(200)];
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() => {
console.log('Await');
let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
});
Using these two methods is not equivalent. Read more about the difference.
In the end, Promise.all is a cleaner approach that scales better to an arbitrary number of tasks.
Actually it depends on your node version, But if you can use async/await then your code will be more readable and easier to maintain.
When you define a function as 'async' then it returns a native Promise, and when you call it using await it executes Promise.then.
Note:
Put your await calls inside a try/catch, because if the Promise fails it issues 'catch' which you can handle inside the catch block.
try{
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
}
catch(ex){
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
}
also you can handle your 'catch' like this:
let result = await your-asyncFunction(parameters).catch((error)=>{//your error handler goes here});
this method mentioned does not produce an exception so the execution goes on.
I do not think there is any performance difference between async/await other than the native Promise module implementation.
I would suggest to use bluebird module instead of native promise built into node.
At this point the only reason to use Promises is to call multiple asynchronous jobs using Promise.all() Otherwise you’re usually better with async/await or Observables.
Its depending upon what approach you are good with, both promise and async/await are good, but if you want to write asynchronous code, using synchronous code structure you should use async/await approach.Like following example, a function return user with both Promise or async/await style.
if we use Promise:
function getFirstUser() {
return getUsers().then(function(users) {
return users[0].name;
}).catch(function(err) {
return {
name: 'default user'
};
});
}
if we use aysnc/await
async function getFirstUser() {
try {
let users = await getUsers();
return users[0].name;
} catch (err) {
return {
name: 'default user'
};
}
}
Here in promise approach we need a thenable structure to follow and in async/await approach we use 'await' to hold execution of asynchronous function.
you can checkout this link for more clarity Visit https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
Yesterday I made a tentative decision to switch from using Promises to using Async/Await, independent of nodejs, based on the difficulty in accessing previous values in the Promise chain. I did come up with a compact solution using 'bind' to save values inside the 'then' functions, but Async seemed much nicer (and it was) in allowing direct access to local variables and arguments. And the more obvious advantage of Async/Await is, of course, the elimination of the distracting explicit 'then' functions in favor of a linear notation that looks much like ordinary function calls.
However, my reading today uncovered problems with Async/Await, which derail my decision. I think I'll stick with Promises (possibly using a macro preprocessor to make the 'then' functions look simpler) until Async/Await gets fixed, a few years from now.
Here are the problems I found. I'd love to find out that I am wrong, that these have easy solutions.
Requires an outer try/catch or a final Promise.catch(), otherwise errors and exceptions are lost.
A final await requires either a Promise.then() or an extra outer async function.
Iteration can only be properly done with for/of, not with other iterators.
Await can only wait for only one Promise at a time, not parallel Promises like Promise chains with Promise.all.
Await doesn't support Promise.race(), should it be needed.
I need help with promises and then callbacks.
I have tried reading guides but don't understand them.
var lastMessage = msg.channel.fetchMessages({ limit: 2 }).then(messages => {
return messages.last();
})
This returns Promise { < pending > }.
.then() statements don't make the program wait for them to be completed, they just execute their code after the Promise they're attached to is resolved.
You can either decide to move the rest of the code inside that .then() statement (but it'll get really messy) or use async/await.
If you are inside a function, you can declare that as an async function: that allows you to use the await keyword inside it. await makes the program wait for a Promise to resolve, and instead of a Promise it returns the value that you would use in the .then() function.
Here's an example:
client.on('message', async () => {
// You can do everything you would normally do here
// Using the 'async' keyword allows you to later user 'await'
var lastMessage = await msg.channel.fetchMessages({ limit: 2 }).then(messages => {
return messages.last();
});
});
Partially adapted from this answer (also mine)
I'm using the bluebird Promise library. From this library I'm using Promise.mapSeries() to perform a mapping operation on a very large list (size=747357).
The code looks as follows (psuedo):
function myFunc(data) {
return Promise.mapSeries(data, handler)
.then((data) => {
console.log('Success!');
return Promise.resolve(data);
})
.catch(console.log);
}
In the handler, I'm doing a couple of things:
Running other Promise functions (recursive)
Returning a new data structure to be stored in the resulting array
In the handler function, I add a console.log('Iter: ', i);.
So then this returns the iter # for each item that's been mapped. It slows and eventually stops at #288. Does this reflect some sort of limit I'm hitting?
I don't understand what the problem is - logic says perhaps this list is too large to handle with Promise.mapSeries.
Any advice or solutions would be appreciated.
Thanks in advance.
UPDATE:
Here's a snippet of the handler function:
function handler(v, i, len) {
return new Promise((resolve, reject) => {
promise
.then((data) => {
return recursivePromiseFn(data)
})
.then((data) => {
let _data = transformData(data);
statusLogger(i);
resolve(_data);
})
})
}
The problem was not with Promise.map or Promise.mapSeries. The problem was an infinite loop in one of my promise functions. This loop seemed to prevent the promise loop from continuing.
A noteworthy comment was that you should avoid using the Promise anti-pattern. This is true but was not the cause of the problem.
I am using Promise.all() within a promise chain. Each promise within the Promise.all() returns a string.
The issue im having is that Promise.all() returns a Promise object to the next promise and I would like to continue the promise chain for each string.
Heres an example:
....
return Promise.all(plugins);
})
.then(function(response) {
console.log(response)
....
The response looks like:
[ 'results from p1', 'results from p2' ]
Is there any way to continue the promise chain for each of the results rather than continuing with a single object containing all results?
Promise.all expects an array of promises. So plugins is an array of promises and all the more: plugin is a Promise.
So you can just chain your plugin Promise.
This would thus become
Promise.all(plugins.map(function(plugin){
return plugin.then(function(yourPluginString){
return 'example '+ yourPluginString;
})
}))
Promise.all(), by its design returns a single promise who's resolved value is an array of resolved values for all the promises you passed it. That's what it does. If that isn't what you want, then perhaps you are using the wrong tool. You can process the individual results in a number of ways:
First, you can just loop over the array of returned results and do whatever you want to with them for further processing.
Promise.all(plugins).then(function(results) {
return results.map(function(item) {
// can return either a value or another promise here
return ....
});
}).then(function(processedResults) {
// process final results array here
})
Second, you could attach a .then() handler to each individual promise BEFORE you pass it to Promise.all().
// return new array of promises that has done further processing
// before passing to Promise.all()
var array = plugins.map(function(p) {
return p.then(function(result) {
// do further processing on the individual result here
// return something (could even be another promise)
return xxx;
});
})
Promise.all(array).then(function(results) {
// process final results array here
});
Or, third if you don't really care when all the results are done and you just want to process each one individually, then don't use Promise.all() at all. Just attach a .then() handler to each individual promise and process each result as it happens.
You can use a tool like https://github.com/Raising/PromiseChain
and implement what you say as
//sc = internalScope
var sc = {};
new PromiseChain(sc)
.continueAll([plugin1,plugin2,plugin3],function(sc,plugin){
return plugin(); // I asume this return a promise
},"pluginsResults")
.continueAll(sc.pluginsResults,function(sc,pluginResult){
return handlePluginResults(pluginResult);
},"operationsResults")
.end();
I didnt test the code if you have any problem PM me
I would like to have a function called on the return of the last promise made during a forEach() loop.
Sample code:
var mainList = getArrayData()
mainList.forEach((item,i)=>{
mongooseSchema.find(_id:item.id).exec((err,doc)=>{
doStuff(doc)
})
})
Any code after the second block will run immediately after all the mongo queries are sent off. If you wrap the whole thing in a promise (i.e. the array data is from a separate mongo query) you still get the same effect.
Is there any way I can have a special function/callback for the last query, or even better, a promise that returns after all the queries have returned?
Thanks
You could use Promise.all. It will fire off once all of the promises in an array are resolved.
The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
var mainList = getArrayData()
let promises = [];
mainList.forEach((item,i)=>{
let p = new Promise((resolve, reject) => {
mongooseSchema.find(_id:item.id).exec((err,doc)=>{
doStuff(doc)
resolve();
});
});
promises.push(p);
});
Promise.all(promises).then(() => {
// do something when all are resolved
});