Function returns before completing her job - javascript

I've written this function, and it returns the values, before doing her job. So the return is allways undefined. How can I get the right results?
The code:
async function isReachable(hostname, port) {
net
.connect(port, hostname, () => {
console.log(true);
return true;
})
.on('error', () => {
console.log(false);
return false;
});
}
The log:
Promise { undefined }
true
Thank you :)

Change the start of your method to this:
async function isReachable(hostname, port) {
return net
.connect(
...
You're missing the return, and you're getting the default undefined return.
isReachable will then return a Promise that you can await for the result

If net.connect() doesn't return a Promise you will need to wrap the function implementation in a Promise and use the resolve() callback to return true/false within the .connect() and .on() callback functions.
function isReachable(hostname, port) {
return new Promise(
(resolve, reject) => {
net
.connect(port, hostname, () => {
resolve(true);
})
.on('error', () => {
resolve(false);
});
}
);
}

If net returns a promise, the correct solution, for me, should contain 'async' accros of 'await'. Take a look at the doc:
The advantage of an async function only becomes apparent when you combine it with the await keyword. await only works inside async functions within regular JavaScript code, however it can be used on its own with JavaScript modules.
await can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.
Something like this:
async function isReachable(hostname, port) {
return netResults = await net
.connect(port, hostname, () => {
console.log(true);
return true;
})
.on('error', () => {
console.log(false);
return false;
});
}

Related

JavaScript: Using Async/Await in a Promise

On the way of learning the concepts of asynchronous JavaScript, I got struggled with the idea behind the situation when they can be chained. As an example consider the following situation: a webhook calls a cloud function and as a requirement there is set a time interval by which the cloud function should response to the webhook. In the cloud function is called an operation for fetching some data from a database, which can be short- or long-running task. For this reason we may want to return a promise to the webhook just to "register" a future activity and later provide results from it e.g.:
async function main () {
return new Promise ((resolve, reject) => {
try {
db.getSomeData().then(data=> {
resolve({ result: data});
});
} catch (err) {
reject({ error: err.message });
}
});
}
Another way is to use async/await instead of a promise for fetching the data, e.g.:
async function main () {
return new Promise (async (resolve, reject) => {
try {
const data = await db.getSomeData();
resolve({ result: data });
} catch (err) {
reject({ error: err.message });
}
});
}
(The code is a pseudo-code and therefore all checks on the returned types are not considered as important.)
Does the await block the code in the second example and prevent returning of the promise?
async functions always return a Promise. It is up to the function caller to determine how to handle it: either by chaining with then/catch or using await. In your example, there is no need to create and return a new Promise.
You could do something like this for example:
async function main () {
try {
const data = await db.getSomeData()
return {result: data}
} catch (err) {
return {error: err.message}
}
}
// On some other part of the code, you could handle this function
// in one of the following ways:
//
// 1.
// Chaining the Promise with `then/catch`.
main()
.then((result) => console.log(result)) // {result: data}
.catch((err) => console.log(err)) // {error: err.message}
// 2.
// Using await (provided we are working inside an asyn function)
try {
const result = await main()
console.log(result) // {result: data}
} catch (err) {
console.log(err) // {error: err.message}
}
Try to avoid combining both methods of handling asynchronous operations as a best practice.

Calling async function from within async function returns undefined

(Forgive me if the title is inaccurate to the problem this one is boggling the mind)
My application requires that I check a value from the request against the database. For this I created an asynchronous function to query the database:
async function checktoken(){
return prisma.$exists.invalidtoken({token: "testtoken"}).then(result => {
return(result)
})
}
I know that the database call on its own works:
prisma.$exists.invalidtoken({token: "testtoken"}).then(result => {
console.log(result) // returns true
})
In the function that fires at every request I try and call checktoken():
async function getUser(token){
var promise = await checktoken()
var result = promise
console.log(result) //undefined
};
Amending the function to include an explicit call to the database works but only when var promise = await checktoken() is defined before it:
async function getUser(token){
var promise = await checktoken() //When this is removed result1 is undefinded
await prisma.$exists.invalidtoken({token: "testtoken"}).then(result1 => {
console.log("inside db call: "+result1) // true
})
};
I think I have a fundamental misunderstanding of async/await but I am not sure exactly what I am missing.
EDIT:
I have updated my approach taking the advice I received and it still does not work. I am beginning to think my ORM is doing something weird:
async function test(token) {
const status = await prisma.$exists.invalidtoken({ token: token });
console.log(status);
return status;
}
test("123") //logs false (as it should)
async function getUser(token){
var status = await test(token) //logs undefined
console.log(status) //logs undefined
};
An async function requires an await. If you are using the promise.then() technique, then what you would want to do is return a new Promise(), and within the .then call back function resolve the promise
function checktoken() {
return new Promise((resolve,reject) => {
prisma.$exists.invalidtoken({token: "testtoken"}).then(result => {
doSomeOtherStuff();
resolve(result);
});
});
}
Is functionally the same as
async checktoken() {
await prisma.$exists.invalidtoken({token: "testtoken"});
}

Promise with Javascript

I'm struggling to understand Promise but it's really difficult for me.
it makes me crazy, I would appreciate your helps.
this is a code and I want "console.log(data)" after Recommend function finished
but the result is undefined.
What should I do?
many thanks
This is app.js
var _promise = function () {
return new Promise((resolve,reject) => {
var data = getJS.Recommend(req.query.User_id)
resolve(data)
}).then(function(data) {
console.log(data)
})
_promise();
}})
this is RecommendPost.js
exports.Recommend =(myId)=>{
var posts=[]
User.find({
User_id : myId
}).then((result)=>{
return User.find()
.select('User_id')
.where('age').equals(result[0].age)
}).then((User_id)=>{
return Promise.all(User_id.map((user,idx,arr)=>{
return Count.find()
.select('board_id')
.where('User_id').equals(user.User_id)
}))
}).then((Users_id)=>{
Users_id.forEach(items=>{
items.forEach(post=>{
posts.push(post.board_id)
})
})
}).then(()=>{
return getMax(posts);
})
}
cf. In RecommendPost.js, the posts works synchronously
//-------- I solved this problem! as some guys said, Recommend function should return Promise. So I edited, then this worked !
this is edited code. thank you for helping me :)
This is app.js
var _promise = function () {
return new Promise((resolve, reject) => {
getJS.Recommend(req.query.User_id).then((data) => {
resolve(data);
})
})
}
_promise().then((data) => { console.log(data) });
this is RecommendPost.js
exports.Recommend =(myId)=>{
return new Promise((resolve,reject)=>{
var posts=[]
User.find({
User_id : myId
}).then((result)=>{
return User.find()
.select('User_id')
.where('age').equals(result[0].age)
}).then((User_id)=>{
return Promise.all(User_id.map((user,idx,arr)=>{
return Count.find()
.select('board_id')
.where('User_id').equals(user.User_id)
}))
}).then((Users_id)=>{
Users_id.forEach(items=>{
items.forEach(post=>{
posts.push(post.board_id)
})
})
}).then(()=>{
resolve (getMax(posts));
})
})
}
It might be clearer for you with async/await that makes asynchronous code look like synchronous:
async function main() {
var data = await getJS.Recommend(req.query.User_id); // waits till its done before going to the next line
console.log(data);
}
// unimportant specific implementation details for live example:
const getJS = {
Recommend(id) {
data = "some data for user ";
return new Promise((res) => setTimeout(() => res(data + id), 1000));
}
}
const req = {
query: {
User_id: 5
}
}
main();
When you call to resolve function is mean that the function is finish and it returns to the caller.
the data object in the then doesn't exist
The Promise.resolve(value) method returns a Promise object that is
resolved with the given value. If the value is a promise, that promise
is returned; if the value is a thenable (i.e. has a "then" method),
the returned promise will "follow" that thenable, adopting its
eventual state; otherwise the returned promise will be fulfilled with
the value.
ES5 :
var _promise = function (req) {
return new Promise((resolve,reject) => {
getJS.Recommend(req.query.User_id).then((data)=>{
console.log(data)
resolve(data)
},(err)=>{
console.log(err)
reject(err);
})
})
}
_promise(req);
ES6
async function _promise(req) {
return await getJS.Recommend(req.query.User_id)
}
For your edit(The entire code):
In this case that Recommend function returns a promise, you don't need the _promise function that wraps it with another one.
and you call it direct
getJS.Recommend(req.query.User_id).then(
(data) => {
console.log(data)
});
Promises means it will always return something, either error or success.
if you resolve something then it will return from there. so your .then part will not execute.
so if you are using resolve and reject params in function then, use .catch method.
return new Promise((resolve,reject) => {
var data = getJS.Recommend(req.query.User_id)
resolve(data)
}) .catch(function (ex) { // in case of error
console.log(ex);
})

How to return from a promise inside then block?

I'm trying to understand how promise's cascading properly works. For this, I created a function which returns a new Promise but has some callback functions in their scope:
exports.function1 = (params) => {
return new Promise((resolve, reject) => {
// do something sync
someFunctionAsyncWithCallback(params, (err, data) => { //async func
err ? reject(err) : resolve(data);
})
}).then(data => {
// do something sync again
anotherAsyncFunctionWithCallback(data, function (err, response) {
return err ? Promise.reject(err) : Promise.resolve(response);
// return err ? reject(err) : resolve(response); ?
});
})
}
Inside then block, how can I made a properly return in order to continue cascading process? In executor there are resolve/reject functions which I can call in order to continue chaining. But, once we are in then execution, these function aren't there - correct me if I'm wrong - and I don't know how to move on.
Any comment will be appreciated.
Avoid combining promise chains with callback-style APIs. Instead, wrap the callback-style API with a promise wrapper, which then lets you compose things reasonably.
The examples you've quoted look like NodeJS APIs. If you're using Node, v8 and higher have utils.promisify which can be used to quickly and easily wrap standard NodeJS-callback-style functions to functions returning promises.
// Get promise-enabled versions:
const promiseSomeFunctionAsyncWithCallback = utils.promisify(someFunctionAsyncWithCallback);
const promiseAnotherAsyncFunctionWithCallback = utils.promisify(anotherAsyncFunctionWithCallback);
// Use them:
exports.function1 = (params) => {
return promiseSomeFunctionAsyncWithCallback(params)
.then(promiseAnotherAsyncFunctionWithCallback);
})
};
If you're not using Node, or you're using an old version, there's nothing magic about utils.promisify, you can easily roll your own:
const promisify = f => return function(..args) {
return new Promise((resolve, reject) => {
f.call(this, ...args, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
Re your comment:
I have some sync code between these callback functions.. How would you handle it in your first example?
There are two styles for that:
1. Put the sync code in the then callback and chain only when you reach your next async bit:
exports.function1 = (params) => {
// Code here will run synchronously when `function1` is called
return promiseSomeFunctionAsyncWithCallback(params)
.then(result => {
// You culd have synchronous code here, which runs when
// this `then` handler is called and before we wait for the following:
return promiseAnotherAsyncFunctionWithCallback(result);
});
})
};
2. Put the sync code in its own then callback:
exports.function1 = (params) => {
// Code here will run synchronously when `function1` is called
return promiseSomeFunctionAsyncWithCallback(params)
.then(result => {
// You culd have synchronous code here, which runs when
// this `then` handler is called.
// Pass on the result:
return result;
})
.then(promiseAnotherAsyncFunctionWithCallback);
})
};
One advantage to #2 is that each distinct logical step is its own block. It does mean one additional yield back to the microtask loop at the end of this iteration of the main event loop, but that's not likely to be an issue.
You need to return another Promise:
return new Promise((res, rej) => anotherAsyncFunctionWithCallback(data, (err, data) => err ? rej(err) : res(data));
However then it would make sense to promisify the function:
const promisify = f => (...args) => new Promise((res, rej) => f(...args, (err, data) => err? rej(err) : res(data)));
const asyncF = promisify(AsyncFunctionWithCallback);
So one can do:
asyncF(1).then(asyncF).then(console.log);
you can use a flag variable for returning something.
example;
async function test(){
let flag=0;
await fetch(request).then(()=> flag=1}
if(flag==1) return;
}

Promise chain with an asynchronous operation not executing in order

I have found other people asking about this topic but I haven't been able to get my promise chain to execute in order.
Here is a basic reproduction of what is happening:
function firstMethod(){
dbHelper.executeQuery(queryParameters).then(result => {
if (result === whatIAmExpecting) {
return dbHelper.doDbOperation(secondQueryParameters)}
else {
throw new Error('An error occurred')
}})
.then(doFinalOperation())
.catch(error => {
})
}
In the above code doFinalOperation() is called before the then function after executeQuery() is called.
Here is the implementation of executeQuery():
function executeQuery(parameter) {
return new Promise((resolve, reject) => {
const queryToExecute = `SELECT * FROM parameter`
return mySqlConnection.query(queryToExecute).then((result) => {
resolve(result)
}).catch(error => {
reject(error)
})
})
And here is the implementation of of the mySqlConnection.query method:
function query(queryString){
return new Promise((resolve, reject) =>
{
initConnection()
connection.connect()
require('bluebird').promisifyAll(connection)
return connection.queryAsync(queryString).then(function(results) {
connection.end();
resolve(results)
}).catch(error => {
reject(error)
})
})
It seems like I have incorrectly implemented the executeQuery() method. The database operation in the mySqlConnection.query is asychronous and I can see that's where the chain of promises stops happening in the expected order.
My question in a nutshell: How do I make the my chain of promises execute in order, and how I do stop a then() method from being executed before the previous Promise has called resolve() or reject()?
Thanks in advance.
then expects a function, but you have accidentally executed it, instead of passing it. Change:
then(doFinalOperation())
with:
then(doFinalOperation)
Now it will be the promise implementation that invokes it (at the proper time), not "you".
If your function needs arguments to be passed, then you can either
(1) Use bind:
then(doFinalOperation.bind(null, parameterOne, parameterTwo, parameterThree))
(2) Use a function expression
then(_ => doFinalOperation(parameterOne, parameterTwo, parameterThree))
Both your .then() methods get called on the first async operation...
Should be something like this:
function firstMethod(){
dbHelper.executeQuery(queryParameters).then(expectedResult => {
if (expectedResult === whatIAmExpecting) {
return dbHelper.doDbOperation(secondQueryParameters)}
.then(doFinalOperation())
.catch(error => {
};
}
else {
throw new Error('An error occurred')
}})
.catch(error => {
});
}

Categories

Resources