Using Promises in NodeJS (Parse Server) - javascript

I am trying to get used to Promises. My Parse Server environment always returns a promise, however I need to mix Parse functions with some of my own functions that I would like to work in accordance with the Parse way of doing things.
Here is my code
savePrescription(user, prescription)
//Returning an object (working!) to be passed to the next function.
.then(function(savedProgData) {
console.log(savedProgData) <-- undefined!
getSavedData(savedProgData)
})
.then(function(savedIds) {
console.log(savedIds); <-- undefined!
sendClientProgrammes(savedIds)
})
.then(function(returnedData) {
console.log(returnedData);
response.success();
}, function(err) {
response.error(err);
})
function sendClientProgrammes(savedIds) {
console.log('running send client programmes');
return new Promise(function(resolve, reject) {
return resolve();
})
}
function getSavedData(savedProgData) {
console.log('running getSavedData');
return new Promise(function(resolve, reject) {
var savedIds = [];
for(var i = 0; i < savedProgData.length; i++) {
savedIds.push(savedProgData[i].id)
}
if(savedIds.length > 0) {
console.log(true);
return resolve(savedIds);
} else {
reject();
}
})
}
At the end of this I am getting a {code: 107, message: "The server returned an invalid response."} error.
How can I 'promisfy' my standard JS functions?

You need to return the results of your functions so the promises are passed down.
.then(function(savedProgData) {
return getSavedData(savedProgData)
})

Related

Porting Promise Chaining from AngularJs to VueJs

Similar to my last question but different enough that I am at a loss. I have the following function in AngularJs that I need to recreate in VueJs. I have two similar ways I've tried to write this in VueJs, but they are causing lots of site exceptions both ways.
AngularJs
var foo = function(obj, config) {
if (config.skip) {
return $q.reject("Skipping");
}
var deferred = $q.defer();
obj.promise = deferred.promise;
if (obj.hasValue()) {
deferred.resolve(obj);
} else {
"/api/callToApi".$promise.then(function(res) {
if (res) {
deferred.resolve(res);
else {
deferred.reject(res);
}
});
}
return deferred.promise;
}
VueJs - take 1. I'm pretty sure this one is missing the actual promise chaining, not sure how to correctly set that.
var foo = function(obj, config) {
let returnEarly = false;
let promise = new Promise((resolve, reject) => {
returnEarly = true;
reject("Skipping"):
}
if (returnEarly) {
return promise;
}
obj.promise = promise;
return new Promise((resolve, reject) => {
if (obj.hasValue()) {
resolve(obj);
} else {
axios.get("/api/callToApi").then(function(res) {
if (res) {
resolve(res);
} else {
reject(res);
}
}
}
}
}
Console errors with take 1
Uncaught (in promise) Error: Request failed with status code 404
at XMLHttpRequest.__capture__.onreadystatechange
VueJs - take 2. I thought this way would return the correct chaining, but I get an error Timeout - Async callback was not invoked within the 5000ms timeout when running jest tests.
var foo = function(obj, config) {
let returnEarly = false;
let promise = new Promise((resolve, reject) => {
returnEarly = true;
reject("Skipping"):
}
if (returnEarly) {
return promise;
}
obj.promise = promise;
return promise.then(() => {
return new Promise((resolve, reject) => {
if (obj.hasValue()) {
resolve(obj);
} else {
axios.get("/api/callToApi").then(function(res) {
if (res) {
resolve(res);
} else {
reject(res);
}
}
}
}
}
}
This is plain JavaScript, not specific to Vue.
It's generally unnecessary to assign a promise to obj.promise because it's returned from the function.
Excessive use of new Promise is known as promise constructor antipattern. If there's already a promise (Axios returns one), there's no need to create a new one, this results in redundant and error-prone code (this can be the reason for Async callback was not invoked... error). In case a new promise needs to be created, there are shortcut Promise methods.
Should be something like:
function(obj, config) {
if (config.skip) {
return Promise.reject("Skipping");
}
if (obj.hasValue()) {
return Promise.resolve(obj);
} else {
return axios("/api/callToApi").then(function(res) {
if (res)
return res;
else
throw res;
}
});
}
}
It's a bad practice in general to make errors anything but Error object.
Also notice that Axios response object is always truthy, possibly needs to be res.data.
Will be more concise when written as async..await.

Recursive promise not resolving

I have a function that fetches some data. If data is not available (it becomes available after some short time), it returns null. I created a function, that returns promise, which is wrapped around logic that fetches data and checks if it is is available - if not, it calls itself:
Foo.prototype.fetchDataWrapper = function () {
return new Promise((resolve, reject) => {
const data = fetchData();
if (data) {
resolve(data)
} else {
setTimeout(() => {
return this.fetchDataWrapper()
}, 100)
}
})
}
Problem is, that despite data is fetched correctly, this promise never resolves. What am I doing wrong?
Your return this.fetchDataWrapper() is returning from the timer callback, no fetchDataWrapper. fetchDataWrapper has already returned. Instead, pass that promise into resolve:
Foo.prototype.fetchDataWrapper = function () {
return new Promise((resolve, reject) => {
const data = fetchData();
if (data) {
resolve(data);
} else {
setTimeout(() => {
resolve(this.fetchDataWrapper()); // *****
}, 100);
}
})
};
When you pass a promise to resolve, it makes the promise resolves belong to resolve or reject based on the promise you pass to it.
(I've also added some missing semicolons to that code. I recommend being consistent with semicolons: Either rely on ASI or don't, both don't mix the two. Also recommend not relying on ASI, but that's a style choice.)
Side note: It would probably make sense to reject after X attempts, perhaps:
Foo.prototype.fetchDataWrapper = function (retries = 5) {
// *** Declare retries param with default -^^^^^^^^^^^
return new Promise((resolve, reject) => {
const data = fetchData();
if (data) {
resolve(data);
} else {
if (retries) { // *** Check it
setTimeout(() => {
resolve(this.fetchDataWrapper(retries - 1));
// *** Decrement and pass on -^^^^^^^^^^^
}, 100);
} else {
reject(); // *** Reject
}
}
})
};

Promise gets rejected even though there is no error. NodeJs

So, I have a piece of code that makes use of Promises and I am using the bluebird library.
The problem is that my promise gets rejected even if there is no error. It completely skips the .then block even for a simple console.log
Here is the code that makes use of promise:
function returnMeetings(query) {
return new Promise((reject, resolve) => {
Meeting.find(query, (err, foundMeetings) => {
if (err) {
console.log("We have a error")
reject(err);
}
resolve(foundMeetings);
})
})
}
And here is the code that makes use of that returnMeetings function
returnMeetings(query)
.then((data) => {
console.log("here we are")
// while (count < stopAt) {
// let localData = [];
// if (req.params.duration === 'monthly') {
// let {
// date1,
// date2
// } = twoDates(count, count);
// localData = data.filter((el) => {
// if (el.startDate) {
// let localDate = new Date(el.startDate);
// if (localDate >= date1 && localDate <= date2) {
// return el;
// }
// }
// })
// if (localData) {
// data.push({
// data: localData,
// month: count
// })
// }
//
// if (count === stopAt - 1) {
// myEmitter.emit('found all meetings')
// } else {
// count++;
// }
// }
// }
}).catch((err) => {
res.status(500).json({
message: err
})
})
As you can see in the returnMeetings function i have placed a console.log inside the if(err) block, and it never runs, from that I conclude that I didn't receive any error from the mongoose query.
Still, the code completely skips the .then block, and falls into the catch chain. I have a simple console.log inside the then block, and an interesting thing to note is that the value of err in the callback inside catch block is an array of mongodb documents.
Can someone explain, why is my code behaving in this manner?
Thanks for your help.
the order of resolve/reject in your Promise constructor callback is wrong ... the names of the functions are irrelevant, the first is to resolve, the second is to reject ... you are actually rejecting the promise when you call resolve
i.e. you could
return new Promise((fred, wilma) => {
then to resolve the promise, you would call fred(value) and to reject you would call wilma(error)
in other words, the names you give the callback arguments is irrelevant, the position is relevant
change your code as follows:
function returnMeetings(query) {
return new Promise((resolve, reject) => {
Meeting.find(query, (err, foundMeetings) => {
if (err) {
console.log("We have a error")
reject(err);
}
resolve(foundMeetings);
})
})
}

How to use another promise in a function which returns a new promise?

I started learning Promises in JS and I am trying to replace my existing callback logic using promises. I wrote a function which returns a new promise, and also uses a promise of a database instance to retrieve the data. However, i am not sure if i am doing it right. Here is the code snippet,
usersService.js
var getUsers = function(queryObject) {
return new Promise(function(resolve, reject) {
dbConnection.find(queryObject)
.then(function(result) {
if (result.length > 0) {
resolve(result)
} else {
resolve(errorMessage.invalidUser())
}).catch(function(err) {
reject(err)
});
})
};
usersRouter.js
router.get('/users', function (req,res,next) {
var queryObject = { "userId":req.query.userId };
userService.getUsers(queryObject)
.then(function (data) { //some logic })
.catch(function (err) { //some logic });
});
Can i use resolve conditionally ?
If the answer is No, what is the right approach ?
Also, am i using the promise in a right manner, in the router?
Thanks in advance!
Since dbConnection.find returns a promise, you can return it directly and choose what will be pass when you will resolve it. No need to wrap it inside an other promise.
var getUsers = function (queryObject) {
return dbConnection.find(queryObject).then(function (result) {
if (result.length > 0) {
return result
} else {
return errorMessage.invalidUser()
}
})
};

Promise.all().then() goes to catch() because then is not recognized

The code is running well until the Promise.all and then is goes right to the catch saying 'then is not defined'.
I've been trying to figure this out without success for hours :(.
Any help are welcome.
Here is a simplified example of code:
// Save
return new Promise((fulfillSave, rejectSave) => {
// Get
this._getObjects().then((object) => {
var promises = [];
// For each value
object.values.forEach((value) => {
promises.push(
// Create promise
new Promise((fulfill, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
})
);
});
// Wait for all promises
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, then((err) => {
// Err
rejectSave(err);
}));
}
}).catch((err) => {
rejectSave(`Error: ${err.message}`);
});
});
Thanks in advance!
Serge.
This is incorrect:
// Wait for all promises
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, then((err) => {
// ^^^^--------------------------- error here
// Err
rejectSave(err);
}));
It's trying to call a freestanding function called then and pass its return value into the then on the object returned by Promise.all.
I think you're trying to hook up a failure handler. If so, you don't say then, you just supply a second function:
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, (err) => {
// Err
rejectSave(err);
}));
But of course, since you're not using the result of that chain and you're just passing the single argument your second function receives into rejectSave, you could just pass rejectSave directly:
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, rejectSave);
If you told us what your overall code is meant to do and what its inputs are, my suspicion is that that code could be a lot simpler. It's common to create and nest promises unnecessarily, and I suspect that's happening here.
For instance, if you just want to do the saves and get back a promise that will resolve when they're all done successfully or reject on the first failure:
return this._getObjects()
.then(objects => Promise.all(objects.map(value => {
return new Promise((resolve, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
});
})));
Or if we give ourselves a helper function for the Mongo bit:
function mongoSavePromise(value) {
return new Promise((resolve, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
});
}
then:
return this._getObjects()
.then(objects => Promise.all(objects.map(mongoSavePromise)));
Avoid the Promise constructor antipattern!
Your whole code should be a simple
return this._getObjects().then(object => {
var promises = object.values.map(value => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
return valueMongoDB.save().catch(err => {
throw 'Error in saving';
});
});
// Wait for all promises
return Promise.all(promises);
}, err => {
throw `Error: ${err.message}`;
});
No unnecessary callbacks, no room for mistakes. Btw, you shouldn't throw strings.

Categories

Resources