How to return promise's value, rather than promise itself in await/async? - node.js

I have the following code. Basically reading a file then return the content.
var result = await promise; return result;
Right now it returns promise itself. Is it a way to return the result straight away?
FileReader.prototype.readInputFile = async function(fileName) {
var condi = this.validateFileName(fileName);
if(condi == true) {
// wrap api, then wait
var promise = new Promise((res, rej) => {
fs.readFile(fileName, { encoding: 'utf-8' }, (err, data) => {
if(err) {
console.log(err);
rej();
}
res(data);
});
});
var result = await promise;
return result;
} else {
// not valid file
}
}

No you cannot. async function itself returns promise only. No matter what you return(or throw) in the body of function, it will eventually become a Promise.resolve() or Promise.reject().

When you call an async function the result is a promise. You can't expect an async function to return the value synchronously, right? So, the promise's value is returned properly. But the promise you see is the promise of the async function, not the one that was resolved inside it.
Put this console.log between these 2 lines and you would see it's an actual value:
var result = await promise;
console.log(result);
return result;

Now I understand, it will return promise instead, not result. I did find a way that it is able to return result, so the code can be nicely.
FileReader.prototype.readInputFile is an async func. If any non-async func calls it, the result will be promise. If any async func call this acync func. The result is actually data.

Related

object Promise on return

Whenever I'm trying to generate random keys from crypto or nanoid (new library) it just returns [object Promise]
async function createCode(length){
if(!length){
return nanoid;
} else {
return nanoid(length);
}
}
// another one for example
async function createCode(){
return await crypto.randomBytes(64).toString('hex');
}
An async function returns a promise by default. Please call await createCode() in another async function or use createCode().then()
All async function return a promise. Always.
So, the caller of an async function has to either use await themselves (from within another async function) or use .then() to get the value out of the promise.
It doesn't look to me like either of your functions benefit from being async. return await someFunc() when someFunc() returns a promise can be done with just return someFunc() just the same. The await is not necessary at all.
FYI, crypto.randomBytes() uses a callback if you want the asynchronous version. If you don't pass it a callback, then it's just a plain synchronous function. Unless you've done something to make a promisified version of that library, it doesn't return a promise.
So, you can just use this:
// another one for example
function createCode(){
return crypto.randomBytes(64).toString('hex');
}
Which you can just call as a regular function:
let randomVal = createCode();
console.log(randomVal);
If you want the asynchronous version and want to use it with promises, then you'd have to promisify it:
// another one for example
function createCode(){
return new Promise((resolve, reject) => {
crypto.randomBytes(64, function(err, val) {
if (err) return reject(err);
resolve(val.toString('hex'));
});
});
}
Then, you can call it:
createCode().then(val => {
console.log(val);
}).catch(err => {
console.log(err);
});

Promise is returning <pending>

I've written a little code snipped for a http request. After I realized request is async, I rewrote my code with a promise. But it's telling me that the promise is pending. I have absolute no idea why it is wrong. Here my code:
function verifyUser(uname,pword){
var options = {
url: 'CENSORED',
method: 'POST',
headers: headers,
form: {'Username':uname, 'Password':pword, 'Key':key},
json:true
}
return new Promise((r,j) => request(options,(error,response,body)=>{
if(error){
console.log("[ERROR] Promise returned error");
throw j(error);
}
r(body);
}))
}
async function receiveWBBData(uspass,passwd){
const data = await verifyUser(uspass,passwd);
return data;
}
var test1 = receiveWBBData("r0b","CENSORED");
console.log(test1);`
Thanks in advance!
receiveWBBData is async. Therefore, test1 is a promise. If you want to log the result, do test1.then(console.log).catch(console.error), or use var test1 = await receiveWBBData(/*...*/) if you want the result in your variable. Note that await can only be used in async functions.
Also, as #somethinghere mentionned, you should not throw your promise rejection, you should return it.
An async function always returns a promise. In order to "unwrap" a promise, you need to await on it, so you need var test1 = await receiveWBBData("r0b","CENSORED");.
Top-level await is not part of the language yet, so I'd recommend you add a function called main() or run() and just call that when your script starts.
async function receiveWBBData(uspass,passwd){
const data = await verifyUser(uspass,passwd);
return data;
}
async function main() {
var test1 = receiveWBBData("r0b","CENSORED");
console.log(test1);`
}
main().catch(error => console.error(error.stack));

Creating functions to chain promises correctly

I am trying to get Promise chaining working for me correctly.
I believe the problem boils down to understanding the difference between:
promise.then(foo).then(bar);
and:
promise.then(foo.then(bar));
In this situation I am writing both foo and bar and am trying to get the signatures right. bar does take a return value that is produced by foo.
I have the latter working, but my question is what do I need to do to get the former working?
Related to the above is the full code (below). I don't have the different logs printed in the order I am expecting (expecting log1, log2, log3, log4, log5, but getting log3, log4, log5, log1, log2). I am hoping as I figure the above I will get this working right as well.
var Promise = require('bluebird');
function listPages(queryUrl) {
var promise = Promise.resolve();
promise = promise
.then(parseFeed(queryUrl)
.then(function (items) {
items.forEach(function (item) {
promise = promise.then(processItem(transform(item)))
.then(function() { console.log('log1');})
.then(function() { console.log('log2');});
});
}).then(function() {console.log('log3')})
).then(function() {console.log('log4')})
.catch(function (error) {
console.log('error: ', error, error.stack);
});
return promise.then(function() {console.log('log5');});
};
What is the difference between promise.then(foo).then(bar); and promise.then(foo.then(bar));?
The second one is simply wrong. The then method takes a callback as its argument, not a promise. That callback might return a promise, so the first one is equivalent to
promise.then(function(x) { return foo(x).then(bar) })
(assuming that foo returns a promise as well).
Your whole code appears to be messed up a bit. It should probably read
function listPages(queryUrl) {
return parseFeed(queryUrl)
.then(function (items) {
var promise = Promise.resolve();
items.forEach(function (item) {
promise = promise.then(function() {
console.log('log1');
return processItem(transform(item));
}).then(function() {
console.log('log2');
});
});
return promise;
}).then(function() {
console.log('log3')
}, function (error) {
console.log('error: ', error, error.stack);
});
}

BlueBird Promises returns "Undefined" when return inside "then" function

Here is my Code:
Checking if user is folowing official Twitter Account (here I've returned new Promise
var isFollowing = function(sender) {
return new promise(function(resolve, reject) {
var following = false;
var params = {
source_id: sender,
target_screen_name: config.get('twitter.official_account')
};
TwitObj.get('friendships/show', params, function(err, data) {
if (!err) {
following = data.relationship.source.following;
resolve(following);
} else {
reject(err);
}
});
});
};
Validation:
var validateMsg = function(dm) {
var sender = getSender(dm);
var result = [];
isFollowing(sender.id)
.then(function(response) {
if (!response) {
result = interactiveMessage(false, lang.__('FOLLOW_MAIN', sender.name));
console.log(result); // Displays as expected
return result; // Not returning value Do I need to return promise again? If yes, WHY?
}
});
};
Main Implementation:
var direct_message = function(msg) {
verifyAccount().catch(function(err) {
console.error(err);
});
var dm = msg.direct_message;
var result = validateMsg(dm);
console.log(result);
};
Questions is how should I force validateMsg function to return result variable inside then function.
Update: While debugging, I got to know that, console.log(response) in
validation function is displaying later after throwing undefined in
"then" function which means program is not able to get response
immediately and due to async nature, I/O is not getting blocked. How
to tackle this?
You're not actually returning anything in the validateMsg function. You're returning a synchronous value ( result ) in the .then function which is a separate function.
The second thing to consider is that you're expecting the validateMsg function, which is asynchronous to behave synchronously.
var result = validateMsg(dm);
The way to achieve what I believe you're looking to do involves making the following changes:
1) Return the promise chain in the validateMsg function.
var validateMsg = function(dm) {
var sender = getSender(dm);
var result = [];
return isFollowing(sender.id)
.then(function(response) {
if (!response) {
result = interactiveMessage(false, lang.__('FOLLOW_MAIN', sender.name));
return result;
}
// Not sure what you want to do here if there is a response!
// At the moment you're not doing anything if the validation
// is successful!
return response;
});
};
2) Change your function call, since you're now returning a promise.
validateMsg(dm).then( function( result ){
console.log( result );
})
3) Consider adding a catch somewhere if only to help you debug :)
validateMsg(dm).then( function( result ){
console.log( result );
})
.catch( function( err ){
console.log( "Err:::", err );
});
The validationMsg function does not have a return value, thus the result in the main function has the value undefined. Try to put return in front of isFollowing so the function returns a promise, then treat validationMsg as a promise.

NodeJs Mongoose How can I get out a data from "find().then" in a "find().then"?

Sorry for my Title, I don't know what can I put.
Can you help me please, I would like to print data from a "then" in a "then" ?
Thank you
models.book.find()
.then( function (content) {
var i = 0;
while (content[i]) {
models.author.findOne({"_id": content[i].author_id}, function(err, data) {
console.log(data); //here, it' good
content[i] = data;
MY_DATA = content;
return MY_DATA;
});
i++;
};
})
.then(function (result) {
console.log(result); // here I would like to print MY_DATA
});
There are a number of problems with your code, and I don't think it's behaving as you're expecting it to.
Chaining Promises
In order to effectively chain promises how you're expecting, each promise callback needs to return another promise. Here's an example with yours changed around a bit.
var promise = models.book.find().exec(); // This returns a promise
// Let's hook into the promise returned from
var promise2 = promise.then( function (books) {
// Let's only get the author for the first book for simplicity sake
return models.author.findOne({ "_id": books[0].author_id }).exec();
});
promise2.then( function (author) {
// Do something with the author
});
In your example, you're not returning anything with your callback (return MY_DATA is returning within the models.author.findOne callback, so nothing happens), so it's not behaving as you're expecting it to.
model.author.findOne is asynchronous
model.author.findOne is asynchronous, so you can't expect to call it multiple times in the callback without handling them asynchronously.
// This code will return an empty array
models.book.find( function (err, books) {
var i = 0, results = [];
while (books[i]) {
models.author.findOne({ "_id": books[i].author_id}, function (err, data) {
// This will get called long after results is returned
results.push(data);
});
i++;
};
return results; // Returns an empty array
});
Handling multiple promises
Mongoose uses mpromise, and I don't see a method to handle multiple promises together, but here's a way your case could be done.
var Promise = require('mpromise');
models.book.find().exec()
.then( function (books) {
var i = 0,
count = 0,
promise = new Promise(),
results = [];
while (books[i]) {
models.author.findOne({ "_id": books[i].author_id }, function (err, author) {
results.push(author);
count++;
// Keep doing this until you get to the last one
if (count === books.length) {
// Fulfill the promise to get to the next then
return promise.fulfill(results);
}
return;
});
}
return promise;
})
.then( function (results) {
// Do something with results
});
I don't know if this will work exactly like it is, but it should give you an idea of what needs to be done.

Resources