JavaScript promise not resolving [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I cannot get this to work, and starting to think I've misunderstood something fundamental. I've been through many examples, and I cannot see what I'm doing wrong.
Here is my promise:
myPromise = new Promise ( resolve => {
if (matchNew(id)) resolve();
})
myPromise.then( () => {
console.log('resolved');
})
matchNew() is a function that simply returns 'true' after completion of save to database. My console confirms this 'true' return happens, but code is not waiting for it, and the promise above never resolves.
Update
This is what I meant regarding the purpose of MatchNew(): It waits for confirmation from MongoDB that the write is successful, then then returns true.
function matchNew(id) {
/* do some stuff */
// update database
MongoPath.Match
.replaceOne( {'_id': m._id}, thisMatch, {writeConcern: { j: true}})
.then( (msg) => {
console.log(msg);
return true;
});
}
I want to ensure my main code is waiting until I get a return values from matchNew before continuing...

matchNew() is a function that simply returns 'true' after completion of save to database.
Thats impossible. It either returns true immeadiately, or it returns a Promise, that resolves to true on completion. Therefore:
if (matchNew(id))
is th same as:
if (new Promise())
and that will enter the branch directly as objects are truthy in javascript. Instead you just want to chain promises:
matchNew(id).then(matches => {
if(matches) {
/*...*/
} else {
/*...*/
}
});

Related

NodeJS : How to return value from function if catch error block is hit [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have a nodejs server that can handle registering users. It interacts with a database and adds a new record given the values passed into it.
function registerUser(user) {
// Misc handling user
var isError = false;
userRepo.create(userData)
.catch((err) => {
isError = true
});
if (isError) {
return "Err"
}
}
The userRepo object is pretty much copied from this tutorial:
https://stackabuse.com/a-sqlite-tutorial-with-node-js/
In the catch block, I can console.log the error, but would like to return a value from the registerUser function if an error occurred. In the above code, the isError assignment inside of the catch block does not modify the isError defined above.
My question is : how can I write this so that a value indicating an error is returned from the registerUser function if an error occurs when creating the record?
That's because userRepo.create is a promise which is created and ran async, so you're getting to the last if part right away and return false.
Instead, you can return from the catch:
function registerUser(user) {
// Misc handling user
return userRepo.create(userData)
.catch((err) => {
return "Err"
});
}
In the caller, on the registerUser(user).then((res) => {... you can check the returned result and see if it's an error or not.

access class property set inside of promise

Coming from a heavy background in PHP I am struggling with some aspects of node/js.
const ldap = require('ldapjs');
class LdapClient {
constructor({
url,
}) {
this.isBound = null;
this.client = ldap.createClient({ url });
}
authenticate(credentials) {
const _this = this;
return new Promise((resolve, reject) => {
return this.client.bind(credentials.username, credentials.password, (err, res) => {
if (err) {
this.client.unbind();
return reject(err);
}
_this.isBound = true;
return resolve(res);
});
});
}
}
const client = new Client({url: ''})
const credentials = {
'username': '',
'password': ''
}
client.authenticate(credentials)
.then(() => {
console.log('authenticated');
console.log('race = ' + client.isBound); // SHOWS TRUE
})
.catch(e => {
console.log(e);
})
console.log(client.isBound); // SHOWS NULL... WANT TRUE (RACE ISSUE as consoles before PROMISE)
I am trying to access the isBound property outside of the promise return where it is set to true inside the authentication method on success.
However as you can see there appears to be a possible race condition?
Is there a way to handle this...
Thanks
It is not a race condition. It's working fine as expected. There are two console.logs in your code. The first one is in promise and the other one is outside the promise.
Your call goes into asynchronous mode, and the last console.log get executed sequentially as the next command in order, which at that time, the value of the variable was null. Your variable resolves later with the correct value.
If you have to perform further actions, you have to do it in the .then() portion of your Client method which will only execute when your Promise has resolved.
For example
Client().then() {//all of your post response related logic should be here}
So you're misunderstanding something about promises. They're meant to be used for Asynchronous code, like so:
let p = new Promise(resolve => setTimeout(resolve, 1000, 'here'))
p.then(console.log)
//in one second 'here'
As you can see the then doesn't actually happen until AFTER the promise resolves. With asynchronous code that's whenever resolve gets called.
So what's happening in your code is as follows:
Create Promise -> set event loop callback
console.log(isBound) // false, but happens first because it's called sync
Promise resolves // true
so really in your promise resolution is the first place you're even going to be able to check it successfully. If you return it from the call you can chain there and make sure the scope is continued later.
let a = 0
let p = Promise.resolve(a)
.then(a =>{
a += 2;
return a;
})
.then(a => console.log(a) || a)
console.log(a) // 0
p == p.then(a =>{
a += 4;
return a;
})
.then(console.log) // false because promises aren't equal and .then/.catch return new promise chains
// 2
// 6
The 2,6 and the false comparison may print out of order because of the event loop, however if you keep it all in the same lexical scope then you'll still have access to a or this within the confines of your promise chain.
Side note: You don't need to reference _this versus this with arrow function inside class methods. They will lexically scope and thus this will be bound to the local scope of that function. More information can be found at You Don't know JS
You're trying to set isBound when the promise is created, not when it's resolved.
Rather than returning the promise directly from the authenticate() method, you can store it in a variable, call .then() on it, and return the promise chain at that point.
authenticate(credentials) {
// create your promise and store it
let authPromise = new Promise((resolve, reject) => {
...
})
// handle the promise and set isBound before returning the chain
return authPromise.then(res => {
_this.isBound = true
return res
})
}
This can be written with fewer lines, but this is meant to illustrate promise chaining and interception before returning.
ADDITIONALLY Your final console.log() is outside of your promise handler (a .then()) so it's always going to be null since that code gets run synchronously, before the authenticate async function has time to complete.
client.authenticate(credentials)
.then(res => {
// you MUST do all your async-dependant operations inside
// promise handlers like this
console.log(client.isBound);
})

Function returns promise object instead of value (async/await) [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I got this code using the async/await :
function _getSSID(){
return new Promise((resolve, reject)=>{
NetworkInfo.getSSID(ssid => resolve(ssid))
})
}
async function getSSID(){
let mySSID = await _getSSID()
if (mySSID == "error") {
return 'The value I want to return'
}
}
And getSSID() is equal to this :
Looks like the getSSID() function will always return a promise. How can I get "The value I want to return" in plain text ?
Any help is greatly appreciated.
Declaring a function async means that it will return the Promise. To turn the Promise into a value, you have two options.
The "normal" option is to use then() on it:
getSSID().then(value => console.log(value));
You can also use await on the function:
const value = await getSSID();
The catch with using await is it too must be inside of an async function.
At some point, you'll have something at the top level, which can either use the first option, or can be a self-calling function like this:
((async () => {
const value = await getSSID();
console.log(value);
})()).catch(console.error):
If you go with that, be sure to have a catch() on that function to catch any otherwise uncaught exceptions.
You can't use await at the top-level.

Let a promise return something [duplicate]

This question already has answers here:
How to block for a javascript promise and return the resolved result? [duplicate]
(2 answers)
Closed 5 years ago.
I have to use a method that returns a promise and that is inside a function. I want to return a value for the parent function in the .then() of the promise.
returnSomething():boolean{
theFunctionThatReturnsAPromise()
.then(
//return true for the returnSomething function here
).catch(
//return false for the returnSomething function here
);
}
How can I do this with typescript/Javascript?
You can use async/await for this.
async function foo() {
try {
var val = await theFunctionThatReturnsAPromise();
console.log(val);
}
catch(err) {
console.log('Error: ', err.message);
}
}
But the return value is still going to be a Promise, since it is asynchronous.
For a better understanding you might want to read this tutorial.
You can't return something directly because the thing you want to return isn't immediately available. That's the whole reason we use asynchronous things like promises. It's hard to know exactly what you are doing from a couple lines of code, but in general you just want to return the promise and allow the caller of the function to deal with it.
For example:
returnSomething():Promise<boolean>{
return theFunctionThatReturnsAPromise()
}
Then the caller can deal with the value like:
returnSomething()
.then(result => {
if (result) { //etc.}
}
.catch( err => { console.log("an error happened", err)}

How do I return the value of a Promise from a function? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I know you can access a Promise’s value inside the .then method like the following code:
const Promise = require("bluebird");
const fs = Promise.promisifyAll(require('fs'));
const mergeValues = require('./helper').mergeValues;
fs.readFileAsync('./index.html', {encoding: "utf8"})
.then((data) => {
return mergeValues(values, data); //async function that returns a promise
})
.then((data) => {
console.log(data);
});
In the above example, I’m reading from a file, merging the data with some values, and then logging the data to the console.
But how about returning the value from a function, as you normally would in a synchronous function? If I follow this comment on synchronous inspection, I think the code should look like this:
function getView(template, values) {
let file = fs.readFileAsync('./' + template, {encoding: "utf8"});
let modifiedFile = file.then((data) => {
return mergeValues(values, data);
});
return modifiedFile.then((data) => {
return modifiedFile.value();
});
}
console.log(getView('index.html', null));
But for some reason, it’s not working. All I’m getting in the console is the Promise object itself, not the value. And when I add the .isFulfilled method on modifiedFile, it outputs to true. So I’m not sure what I’m doing incorrectly.
Promises don't work that way. They are asynchronous by nature, so you can't interact with them in the same way you do with synchronous code.
That means you have to use the then method to get at the value:
function getView(template, values) {
let file = fs.readFileAsync('./' + template, {encoding: "utf8"});
let modifiedFile = file.then((data) => {
return mergeValues(values, data);
});
return modifiedFile.then((data) => {
return modifiedFile.value();
});
}
// This won't work
// console.log(getView('index.html', null));
// instead:
getView('index.html', null).then(function (view) {
console.log(view);
});
So I’m not sure what I’m doing incorrectly.
You're not doing anything incorrectly, actually. You just can't use promises like a normal return value from a function. Period.

Categories