I would like to use await method inside the async.Series
Here is my node js code
const async = require("async");
async.eachSeries(myArr, function (arr, callback) {
let test = await db.collection('coll').findOne({ _id: arr }); //I couldn't use await here
callback(null, test);
}, function (err) {
console.log("Done");
});
I have tried
async.eachSeries(myArr, async function (arr, callback) {
let test = await db.collection('coll').findOne({ _id: arr }); //It not working here
callback(null, test);
}, function (err) {
console.log("Done");
});
And
async.eachSeries(myArr, async.asyncify(async(function (arr, callback) {
let test = await db.collection('coll').findOne({ _id: arr }); //It not working here
callback(null, test);
})), function (err) {
console.log("Done");
});
Correct me If the approach is wrong or let me know how to achieve await inside the async each.
As async document said:
Using ES2017 async functions Async accepts async functions wherever we
accept a Node-style callback function. However, we do not pass them a
callback, and instead use the return value and handle any promise
rejections or errors thrown.
If you still pass the callback function as the second parameter of eachSeries 's callback function, it will not work as expected. Just remove
callback and return the result:
async.eachSeries(myArr, async (arr) => { // remove callback parameter
const test = await db.collection('coll').findOne({ _id: arr }); // wait the response
// ...
return test; // return response
}, function (err) {
console.log("Done");
});
Or just use for...loop instead of eachSeries:
// inside a async function
for (const i of myArr) {
const test = await db.collection('coll').findOne({ _id: arr });
// Do something with `test`
}
console.log("Done");
Why mix callbacks with promises?
Right aproach will be use an async iterator Symbol.
If not first attempt would be valid
eachSeries(array, async function(arr, cb) {
await ....
});
Related
I am using Node.js (I am at beginners level) and Google Cloud Firestore and I am having issues with having my map function to wait for my getStuff()-function, and will instead return a Promise rather than the value/text itself.
I have two functions like this:
function getUserData() {
return db.collection('users').get()
.then((querySnapshot) => {
var docs = querySnapshot.docs.map(doc => [doc.data(), doc.id, getStuff(doc.id)])
console.log(docs)
return docs
});
}
function getStuff(doc_id) {
return db.collection('users').doc(doc_id).collection('tweets').limit(1).get()
.then((querySnapshot) => {
var docs = querySnapshot.docs.map(doc => doc.data());
console.log("TWEETS", doc_id, docs[0]['text']);
return docs[0]['text']
});
}
The getStuff() function produces a console log result as:
TWEETS DAU86mxIhmD6qQQpH4F God’s country!
TWEETS JQHTO0jUjAodMQMR6wI I’m almost there Danny!
whereas the console.log(docs) in getUserData() returns:
[
{
name: "John McClane",
twitter: 'john4'
},
'Yn4rEotMR02jEQSqdV4',
Promise { <pending> } // <- This is where the tweet should have been
]
I am not to familiar with Promises and await/async and I can't get that to work. How do I set up my getUserData-function so that it will provide the Tweet text and not a Promise { pending }?
since getStuff() returns a promise you need to await it to resolve.
async function getUserData() {
return db.collection('users').get()
.then((querySnapshot) => {
var promises = querySnapshot.docs.map(async doc => {
var stuff = await getStuff(doc.id)
return [doc.data(), doc.id, stuff]
})
var docs = await Promise.all(promises)
console.log(docs)
return docs
});
}
the getStuff() function returns a promise. one ways to resolve the promise is to use await.
Call the function using an await keyword. await keyword can be used only inside a async function so make the callback into a async function.
function getUserData() {
return db.collection('users').get()
.then( async (querySnapshot) => {
var docs = querySnapshot.docs.map(doc => [doc.data(), doc.id, await getStuff(doc.id)])
console.log(docs)
return docs
});
}
I haven't tested out my code, but it should work.
I'm beginner in nodejs, This function returns "Promise {pending}
" I Appreciate any help.
Thanks
async function getCurrentUser(id){
try{
let user = User.findOne({id:id})
return user;
}catch(err){
return err;
}
}
You missing the await in front of some function that return a Promise
let user = await User.findOne({id:id})
Promise is an immutable async operation that need time to finish so you either use async/await like you did or chain the promise with .then call like
User.findOne({ id })
.then((response) => {
// do sth with the resposne
});
recommend you to read Async & Performance from YDKJS series
full rewrite of code:
async function getCurrentUser(id) {
try {
let user = await User.findOne({ id: id })
return user;
} catch (err) {
return err;
}
}
// getCurrentUser usage
async function doSth(){
let user = await getCurrentUser();
}
usage clarification:
putting async in front of a function make this function return type a promise no matter what you return inside it so the only two way to use such a function is just like how you use a promise either use it in another async function using await or use .then() chaining function
u missing await
async function getCurrentUser(id){
try{
let user = await User.findOne({id:id})
return user;
}catch(err){
return err;
}
I want to use the async function to bring out a particular value from my database to my the function global so I can use it in other parts of my application.
async function dimension() {
const result = await Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
console.log(holder) /// this print the expected result, that i want to make global
});
return {
result
};
};
console.log(dimension())
but the console.log of the dimension() gives me this
Promise { <pending> }
instead of the same value that
console.log(holder)
gives me nothing.
The problem is you are printing the result of dimension() as soon as you call it, but since this function is async, it returns a promise that is not yet resolved.
You do not need to use async/await here. Settings.find() seems to return a Promise. You can just return directly this Promise and use .then() to do something once that promise is resolved.
Like this :
function dimension () {
return Settings.find({ _id: '5d7f77d620cf10054ded50bb' }, { dimension: 1 }, (err, res) => {
if (err) {
throw new Error(err.message, null);
}
return res[0].dimension;
});
}
dimension().then(result => {
//print the result of dimension()
console.log(result);
//if result is a number and you want to add it to other numbers
var newResult = result + 25 + 45
// the variable "newResult" is now equal to your result + 45 + 25
});
More info on Promises and async/await
You have to await for your result, like this:
const result = await dimension();
console.log(result);
In that case, you don't even to make the original function async, just write it like this:
function dimension() {
return Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
});
};
async function myGlobalFunc() {
const result = await dimension();
console.log(result);
}
The best way to have this globally available is to just put your function dimension in a file somewhere. Then where you need the value, you just require it and await its value. E.g.
// get-dimension.js
// ...const Settings = require... comes here
module.exports = function getDimension() {
return Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
});
}
// your other modules, e.g.
// my-service-handler.js
const getDimesion = require('./get-dimension');
async function myServiceHandler() {
const dimension = await getDimension();
// do stuff with dimension.
}
You're using async/await, but you're mixing it with callbacks, this is not desirable as it leads to confusion. It's not clear what you expect to happen in the callback, but return holder; likely doesn't do what you expect it to do, returning from a callback does not work the same way returning from a promise handler works. Your entire implementation should work with promises so that the async/await syntax reads more naturally (as it was intended).
async function dimension() {
// We're already awaiting the result, no need for a callback...
// If an error is thrown from Settings.find it is propagated to the caller,
// no need to catch and rethrow the error...
const res = await Settings.find({_id: "5d7f77d620cf10054ded50bb"}, {dimension: 1});
return {result: res[0].dimension};
}
(async () => {
try {
console.log(await dimension());
} catch (err) {
console.error(err);
}
})();
Use dimension().then() in your code then it will work fine.
async function globalDimension() {
const data = await Users.findOne({ phone: 8109522305 }).exec();
return data.name;
}
globalDimension().then(data => {
console.log(data);
});
I made a request inside my Node server to Elasticsearch. This is working perfect, except that I always get a promise returned instead of the results.
When I console log the results they look perfect, but when I return them I either get nothing or a promise.
Can someone tell me the proper way to retrieve, and handle the data from Elasticsearch?
I am using VueJS with a Node server and the official Elasticsearch package.
function getNewTest(client)
{
client.search({
index: 'myIndex',
}).then(function(resp) {
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
}
let tests = getNewTest(client);
console.log(tests);
# Output: Promise { <pending> }
EDIT:
As suggested I tried both codes, both didnt work. I changed my own code, now it returns an "undefined" to me.
getNewTest(client).then(function (response) {
console.log(response);
});
will return "undefined" to me. I changed my function to this:
async function getNewTest(client)
{
await client.search({
index: 'myIndex',
}).then(function(resp) {
console.log(resp.hits.hits, 'returned');
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
}
When I would do
let test = getNewTest(client);
it returns a promise to me.
(async () => {
let tests = await getNewTest(client);
console.log(tests);
})();
You are making a db call, so the main thread becomes free and start executing the next line. The code needs to wait till the promise is resolved and then execute the next line.
Or if you dont want to use async await, you can use this code below -
async function getNewTest(client) {
client.search({
index: 'myIndex',
}).then(function (resp) {
return resp.hits.hits;
}, function (err) {
console.trace(err.message);
});
}
getNewTest(client).then(result => {
console.log(result);
});
Function getNewTest will alway return undefined because you do not explicitly return anything.
Even if you did it this way :
function getNewTest(client)
{
return client.search({
index: 'myIndex',
}).then(function(resp) {
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
}
It will return a promise.
const generatePromise = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1500)
}, 500)
})
function test () {
return generatePromise()
.then((data) => console.log('after promise resolved ', data))
.catch((err) => console.log(err))
}
console.log('before calling test function');
const result = test()
console.log('after calling test function', result instanceof Promise);
When we call a function that returns a promise (async work) the execution does not wait for the promise to resolve it continue executing other code, that why const result = test() won't have the result of the promise.
The result of the promise will only be available inside the then handler as you can see in the code snippet.
const generatePromise = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1500)
}, 500)
})
function test () {
return generatePromise()
}
console.log('before calling test function');
test()
.then((data) => console.log('after promise resolved ', data))
.catch((err) => console.log(err))
console.log('after calling test function');
You can achieve the required using async & await:
const generatePromise = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1500)
}, 500)
})
// async function always returns promise even if you did't explicitly do
async function test () {
const data = await generatePromise();
// you can access resolved data here
console.log('after promise resolved ', data);
return data;
}
// first without then
console.log('before calling test function');
// you can't access it here unless you use then
// test().then(data => console.log(data));
const result = test();
console.log('after calling test function', result instanceof Promise);
This is how asynchronous works you can't return a promise and expect to receive the results instantly you can access the results inside the then handles or use await as I did.
When you do this:
async function getNewTest(client)
{
await client.search({
index: 'myIndex',
}).then(function(resp) {
console.log(resp.hits.hits, 'returned');
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
}
it means this:
async function getNewTest(client)
{
await client.search({
index: 'myIndex',
}).then(function(resp) {
console.log(resp.hits.hits, 'returned');
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
return undefined; // you are deliberately returning undefined
}
Remember that in javascript if you don't return anything the result of the function is undefined. I'm guessing what you intend to do is:
async function getNewTest(client)
{
return await client.search({ // NOTE THIS LINE
index: 'myIndex',
}).then(function(resp) {
console.log(resp.hits.hits, 'returned');
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
}
Since .search() already returns a Promise (or promise-like object) you don't need to await for it. The code above is exactly the same as:
function getNewTest(client)
{
return client.search({ // NOTE THIS RETURN
index: 'myIndex',
}).then(function(resp) {
console.log(resp.hits.hits, 'returned');
return resp.hits.hits;
}, function(err) {
console.trace(err.message);
});
}
But still, this does not allow you to do let test = getNewTest(client). Nothing will ever make this possible. It is simply impossible. To get the result of getNewTest() either call it's .then() method or await for it. In other words, either do this:
getNewTest(client).then(function(test) { /*continue logic here*/ })
or do this:
async function foo () {
let test = await getNewTest(client);
/*continue logic here*/
}
foo();
Note that this mechanism applies everywhere. It is also impossible to do this:
async function foo () {
let test = await getNewTest(client);
return test;
}
let test = foo();
You must instead do this if you want to go this route:
async function foo () {
let test = await getNewTest(client);
return test;
}
async function bar () {
let test = await foo();
/*continue logic here*/
}
There is no escape. You can never directly return an asynchronous value.
I am getting Result is: [object Promise] when I am calling this promise. I want to be able to work with the data that comes out of it. I am expecting the result to be an array of messages from my SQS queue.
I currently have more than 10 messages in the queue so should be fine finding some.
This is my code currently:
let params = {
QueueUrl: config.aws.serviceQueue,
VisibilityTimeout: 60,
MaxNumberOfMessages: 10
};
let getMonitors = sqs.receiveMessage(params).promise();
let result = getMonitors.then(function(data) {
console.log('Success');
return data;
}).catch(function(err) {
console.log(err);
});
console.log(`Result is: ${result}`);
What am I missing here? I am very new to promises so please bear with me if I don't understand your answer or question.
Yeah, the result of getMonitors().then() is a promise object so the result variable is indeed a promise object. That's how promises work.
If you want to access the value inside the promise, you either use .then() on the promise or you use await (inside an async tagged function).
In this particular code, you should just be consuming the result inside your .then() handler. That's where you have the value.
You return something in then and try to assign it to any variable you will end up with having promise.
What you can do is
let params = {
QueueUrl: config.aws.serviceQueue,
VisibilityTimeout: 60,
MaxNumberOfMessages: 10
};`
let getMonitors = sqs.receiveMessage(params).promise();
/*let result = getMonitors.then(function(data) {
console.log('Success');
return data;
}).catch(function(err) {
console.log(err);
});*/
//console.log(``Result is: ${result}``);`
getMonitors.then(function (result) {
console.log(result);
}).catch(function (err) {
console.log(err);
});
or you can use Async and await ::
const someFunction = Async() => {
/* your all code inside*/
let result = await getMonitors();
console.log(Result is: $ {
result
});
or
console.log(Result is: $ {
await result
});
}
You might be trying to look at the data before the promise has resolved. Async/ await will probably help.
async function happyLittleFunc() {
const params = {
QueueUrl: config.aws.serviceQueue,
VisibilityTimeout: 60,
MaxNumberOfMessages: 10
};
let getMonitors;
try {
getMonitors = await sqsReceieveMessage(params);
} catch (err) {
console.log(err);
return;
}
console.log(`Result is: ${getMonitors}`);
}
// Call sqs
function sqsReceieveMessage(params) {
return new Promise(async (resolve, reject) => {
let messageData;
try {
messageData = await sqs.receiveMessage(params);
} catch (err) {
reject(err);
}
resolve(messageData);
});
}
happyLittleFunc();