bluebird pattern for mocking asynchronous promises with syncronous code - node.js

I'm just getting started with bluebird (and node more generally).
I am wanting to create some mocks (for what will ultimately be either http or database calls).
All the talk of antipatterns has me anxious :-)
So is this a reasonable approach for converting this synchronous code into promises?
I have two simple functions here. The second calls the first (not in way the prod service would) but it serves as an illustration of nesting promises.
// mock function to return a promise of a collection
var getTestPatients = function(params) {
return new Promise(function(resolve, reject) {
setTimeout(function() {resolve(test_patients);}, 200);
})
};
// mock function to return a promise of an object
var getTestPatient = function(params) {
return getTestPatients().then(function(patients) {
// wouldnt get entire patient list in prod - but this works for a mock
var patient = _.find(patients, {urn: params.urn});
if (patient) {
patient.reviews = testReviews(params.uid);
}
else {
throw new Error('patient not found');
}
return Promise.resolve(patient);
});
};
A couple of things these are demonstrating:
creating a fake delay
creating a promise from synchronous code
manipulating a promise result within a function that makes a promise
throwing errors
So quite a few things I could have gotten wrong.
How did I do? Any anti-patterns in here? or other rookie errors?

No antipatterns and no mistakes to see here. However, two things you could improve:
Whenever you find yourself using the Promise constructor, first try to find a simpler way. Is there already a function that does return a promise for the desired task? setTimeout is a genuine callback-based API, so nothing wrong here, but given that you're using Bluebird you could remove that boilderplate by just using the Promise.delay helper function:
function getTestPatients = function(params) {
return Promise.delay(test_patients, 200);
}
The call to Promise.resolve in the then handler is unnecessary. Just as you can throw exceptions, you can return plain values and they will be automatically wrapped. So cleaner-looking is just
return patient;

Related

Retrieving a value in a function in Node.js

I'm struggling with callbacks in Node.js. I simply want playerNumber to be set to the number of players in my collection of Players. The console.log works, but I can't get the variable out of the function and into the playerNumber variable.
And if there's a simpler way get this value for use in the rest of my backend code, I'm all ears. I'm clearly new at Node.js, but the code always seems more involved than I'm expecting.
Thanks in advance!
var playerNumber = function countPlayers(callback){
Player.count(function(err, numOfDocs) {
console.log('I have '+numOfDocs+' documents in my collection');
callback(err, numOfDocs);
});
}
It's probably async, and it's a typical first-timer experience to want to "get back to normal" on the call chain on the way back from async call. This can't be done, but it's not so bad to live with it. Here's how...
Step 1: Promises are better than callbacks. I'll leave the long story
to others.
Step 2: Callbacks can be made into promises
In the OP case...
// The promise constructor takes a function that has two functions as params
// one to call on success, and one to call on error. Instead of a callback
// call the 'resolve' param with the data and the 'reject' param with any error
// mark the function 'async' so callers know it can be 'await'-ed
const playerNumber = async function countPlayers() {
return new Promise((resolve, reject) => {
Player.count(function(err, numOfDocs) {
err ? reject(err) : resolve(numOfDocs);
});
});
}
Step 3: Yes, the callers must deal with this, and the callers of the callers, and so on. It's not so bad.
In the OP case (in the most modern syntax)...
// this has to be async because it 'awaits' the first function
// think of await as stopping serial execution until the async function finishes
// (it's not that at all, but that's an okay starting simplification)
async function printPlayerCount() {
const count = await playerNumber();
console.log(count);
}
// as long as we're calling something async (something that must be awaited)
// we mark the function as async
async function printPlayerCountAndPrintSomethingElse() {
await printPlayerCount();
console.log('do something else');
}
Step 4: Enjoy it, and do some further study. It's actually great that we can do such a complex thing so simply. Here's good reading to start with: MDN on Promises.

Mongoose: How do I avoid callback hell whilst allowing for stubbing of mongoose methods that do not return promises?

In my express node application written in typescript, I'm using mongoose and am trying to avoid callback hell whist allowing for stubbing the mongoose functions in my mocha/sinon unit tests.
Where mongoose does not return a promise (e.g. Model.count()) I'm wrapping the call in a new (awaited) promise which is resolved/rejected in the callback, like so:
const myModelCount = await new Promise((resolve, reject) => {
MyModel.count({}, (err, count) => {
if (err) {
reject(err);
return;
}
resolve(count);
});
});
This works great but I don't know how I can unit test the containing function and avoid a timeout error due to the unresolved promise. I want to stub MyModel.count so that it does not attempt to call the database, but how do I stub it so that the awaited promise is resolved and the program continues?
Doing something like:
sinon.stub(MyModel, 'count').returns(Promise.resolve(1));
does not work as it does not resolve the promise that is being awaited, and since I don't have access to the resolve/reject parameters I don't know how to resolve the promise in the stub.
Is there a way I can make the above work, or alternatively how I can refactor my code to both avoid callback hell and so that I can stub out the mongoose functions in unit tests?
Regarding returned promises, there seems to be a misunderstanding (easy to have with mongoose) with the model count method. It returns a query object if called without a callback and, as with all query objects, when invoked by exec() (also without a callback) will return a promise.
mongoose.Promise = global.Promise; // This sets the mongoose internal Promise to the native Promise, while it is not necessary it is highly advised.
const promise = MyModel.count().exec();
As far as testing, if the unit test is meant to test that a wrapper function is simply calling the wrapped function then I find this to be more of a functional test as any test should only be concerned with the inputs/outputs of a function (the API of the function) and not the inner workings (the implementation of the function). In other words the function should be a black box to any tests so that if the implementation were to change but the API remains constant then the tests should continue to pass.
That said if you really want to stub the model count/exec out then something like the following might work (pseudo coding here):
sinon.stub(MyModel, 'count').returns({
exec() { return Promise.resolve(1); }
});
Hope this clears up some possible confusion and helps!

How to return promise to the router callback in NodeJS/ExpressJS

I am new to nodejs/expressjs and mongodb. I am trying to create an API that exposes data to my mobile app that I am trying to build using Ionic framework.
I have a route setup like this
router.get('/api/jobs', (req, res) => {
JobModel.getAllJobsAsync().then((jobs) => res.json(jobs)); //IS THIS THe CORRECT WAY?
});
I have a function in my model that reads data from Mongodb. I am using the Bluebird promise library to convert my model functions to return promises.
const JobModel = Promise.promisifyAll(require('../models/Job'));
My function in the model
static getAllJobs(cb) {
MongoClient.connectAsync(utils.getConnectionString()).then((db) => {
const jobs = db.collection('jobs');
jobs.find().toArray((err, jobs) => {
if(err) {
return cb(err);
}
return cb(null, jobs);
});
});
}
The promisifyAll(myModule) converts this function to return a promise.
What I am not sure is,
If this is the correct approach for returning data to the route callback function from my model?
Is this efficient?
Using promisifyAll is slow? Since it loops through all functions in the module and creates a copy of the function with Async as suffix that now returns a promise. When does it actually run? This is a more generic question related to node require statements. See next point.
When do all require statements run? When I start the nodejs server? Or when I make a call to the api?
Your basic structure is more-or-less correct, although your use of Promise.promisifyAll seems awkward to me. The basic issue for me (and it's not really a problem - your code looks like it will work) is that you're mixing and matching promise-based and callback-based asynchronous code. Which, as I said, should still work, but I would prefer to stick to one as much as possible.
If your model class is your code (and not some library written by someone else), you could easily rewrite it to use promises directly, instead of writing it for callbacks and then using Promise.promisifyAll to wrap it.
Here's how I would approach the getAllJobs method:
static getAllJobs() {
// connect to the Mongo server
return MongoClient.connectAsync(utils.getConnectionString())
// ...then do something with the collection
.then((db) => {
// get the collection of jobs
const jobs = db.collection('jobs');
// I'm not that familiar with Mongo - I'm going to assume that
// the call to `jobs.find().toArray()` is asynchronous and only
// available in the "callback flavored" form.
// returning a new Promise here (in the `then` block) allows you
// to add the results of the asynchronous call to the chain of
// `then` handlers. The promise will be resolved (or rejected)
// when the results of the `job().find().toArray()` method are
// known
return new Promise((resolve, reject) => {
jobs.find().toArray((err, jobs) => {
if(err) {
reject(err);
}
resolve(jobs);
});
});
});
}
This version of getAllJobs returns a promise which you can chain then and catch handlers to. For example:
JobModel.getAllJobs()
.then((jobs) => {
// this is the object passed into the `resolve` call in the callback
// above. Do something interesting with it, like
res.json(jobs);
})
.catch((err) => {
// this is the error passed into the call to `reject` above
});
Admittedly, this is very similar to the code you have above. The only difference is that I dispensed with the use of Promise.promisifyAll - if you're writing the code yourself & you want to use promises, then do it yourself.
One important note: it's a good idea to include a catch handler. If you don't, your error will be swallowed up and disappear, and you'll be left wondering why your code is not working. Even if you don't think you'll need it, just write a catch handler that dumps it to console.log. You'll be glad you did!

should i use `return` in Promise?

function saveToTheDb(value) {
return new Promise(function(resolve, reject) {
db.values.insert(value, function(err, user) { // remember error first ;)
if (err) {
return reject(err); // don't forget to return here
}
resolve(user);
})
}
}
Here is the code which i see from here.
i am confused about return keyword.
For resolve(user);, do i need return?
For reject(user);, do i need return?
There is no need to use a return statement inside a new Promise() callback. The Promise constructor is not expecting any sort of return value from the callback.
So, the reason to use a return statement inside that callback is only to control the flow of execution in that function. If you want execution inside your callback to finish and not execute any more code within that callback, you can issue a return; at that point.
For example, you could have written your code like this with no return statement:
function saveToTheDb(value) {
return new Promise(function(resolve, reject) {
db.values.insert(value, function(err, user) {
if (err) {
reject(err);
} else {
resolve(user);
}
});
}
}
In this case, you used the if/else clause to make sure the flow of control in your function takes the correct path and no return was needed or used.
A common shortcut when promisifying async functions like this is:
function saveToTheDb(value) {
return new Promise(function(resolve, reject) {
db.values.insert(value, function(err, user) {
if (err) return reject(err);
resolve(user);
});
}
}
This is not functionally different than the previous code block, but it is less typing and more compact. The return statement in front of reject(err); is only for flow of control reasons to prevent from executing the resolve(user); statement in case of error since the desired flow of control is to call reject(err) and then not execute anything else in the callback.
In fact, the return statement in this last block is not actually even needed in this specific case because executing a resolve() after a reject() will not do anything since promises are latched to whichever happens first resolve or reject. But, it is generally considered poor practice to execute unnecessary code so many would argue that it is better to use flow of control structures such as if/else or return to only execute the code that is needed.
So, this would technically work too, but is not considered a best practice because it executes unnecessary code and isn't as clearly structured:
function saveToTheDb(value) {
return new Promise(function(resolve, reject) {
db.values.insert(value, function(err, user) {
if (err) reject(err);
resolve(user);
});
}
}
FYI, what you are doing here is called "promisifying" which makes a regular async function that works with a callback into a function that returns a promise. There are libraries and functions that will "promisify" a function or a whole object of functions (e.g. a whole API) for you in one function call so you don't have to do this manually. For example, I regularly use Bluebird which offers Promise.promisify() for promisifying a single function or Promise.promisifyAll() which will promisify all the methods on an object or prototype. This is very useful. For example, you could get promisified versions of the entire fs module with just this:
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
Then, you can use methods that return a promise such as:
fs.readFileAsync("file.txt").then(function(data) {
// do something with file.txt data here
});
Generally, in NodeJS, you shouldn't use the promise constructor very much.
The promise constructor is for converting APIs that don't return promises to promises. You should consider using a library that provides promisification (even if you use native promises all-around) since it provides a safe alternative that does not have subtle errors with error-handling logic.
Automatic promisification is also considerably faster.
That said, the answer to your question is "Yes".
It is perfectly safe to do so, there is nothing special about promise constructors - they are just plain JavaScript. Domenic discusses the design of the promise constructor in his blog.
It is perfectly safe (just like any other function) to return early - it is actually quite common in regular asynchronous functions.
(Also, in your example code you should just use Promise.resolve, but I assume it was that simple only because it is an example).
Copied this answer from duplicate
As #JaromandaX said in this case the return statement does not make any diference.
From the docs:
In all cases where a promise is resolved (i.e. either fulfilled or rejected), the resolution is permanent and cannot be reset. Attempting to call resolve, reject, or notify if promise is already resolved will be a no-op.

Node.js: serial operations with branching

I'm new to node.js and using it for a backend that takes data from syslog messages and stores it to a database.
I've run into the following type of serial operations:
1. Query the database
2. If the query value is X do A. otherwise do B.
A. 1. Store "this" in DB
2. Query the database again
3. If the query value is Y do P. otherwise do Q.
P. Store "something"
Q. Store "something else"
B. 1. Store "that" in the DB
2. Store "the other thing" in the DB
The gist here is that I have some operations that need to happen in order, but there is branching logic in the order.
I end up in callback hell (I didn't know what that is when I came to Node.. I do now).
I have used the async library for things that are more straight forward - like doing things in order with async.forEachOfSeries or async.queue. But I don't think there's a way to use that if things have to happen in order but there is branching.
Is there a way to handle this that doesn't lead to callback hell?
Any sort of complicated logic like this is really, really going to benefit from using promises for every async operation, especially when you get to handling errors, but also just for structuring the logic flow.
Since you haven't provided any actual code, I will make up an example. Suppose you have two core async operations that both return a promise: query(...) and store(...).
Then, you could implement your above logic like this:
query(...).then(function(value) {
if (value === X) {
return store(value).then(function() {
return query(...).then(function(newValue) {
if (newValue === Y) {
return store("something");
} else {
return store("something else");
}
})
});
} else {
return store("that").then(function() {
return store("the other thing");
});
}
}).then(function() {
// everything succeeded here
}, function(err) {
// error occurred in anyone of the async operations
});
I won't pretend this is simple. Implemented logic flow among seven different async operation is just going to be a bit of code no matter how you do it. But, promises can make it less painful than otherwise and massively easier to make robust error handling work and to interface this with other async operations.
The main keys of promises used here are:
Make all your async operations returning promises that resolve with the value or reject with the failure as the reason.
Then, you can attach a .then() handler to any promise to see when the async operation is finished successfully or with error.
The first callback to .then() is the success handler, the second callback is the error handler.
If you return a promise from within a .then() handler, then that promise gets "chained" to the previous one so all success and error state becomes linked and gets returned back to the original promise state. That's why you see the above code always returning the nested promises. This automates the returning of errors all the way back to the caller and allows you to return a value all the way back to the caller, even from deeply nested promises.
If any promise in the above code rejects, then it will stop that chain of promises up until an actual reject handler is found and propagate that error back to that reject handler. Since the only reject handler in the above code is at the to level, then all errors can be caught and seen there, no matter how deep into the nested async mess it occurred (try doing that reliably with plain callbacks - it's quite difficult).
Native Promises
Node.js has promises built in now so you can use native promises for this. But, the promise specification that node.js implements is not particularly feature rich so many folks use a promise library (I use Bluebird for all my node.js development) to get additional features. One of the more prominent features is the ability to "promisify" an existing non-promise API. This allows you to take a function that works only with a callback and create a new function that works via a promise. I find this particularly useful since many APIs that have been around awhile do not natively return promises.
Promisifying a Non-Promise Interface
Suppose you had an async operation that used a traditional callback and you wanted to "promisify it". Here's an example of how you could do that manually. Suppose you had db.query(whatToSearchFor, callback). You can manually promisify it like this:
function queryAsync(whatToSearchFor) {
return new Promise(function(resolve, reject) {
db.query(whatToSearchFor, function(err, data) {
if (!err) {
reject(err);
} else {
resolve(data);
}
});
});
}
Then, you can just call queryAsync(whatToSearchFor) and use the returned promise.
queryAsync("foo").then(function(data) {
// data here
}, function(err) {
// error here
});
Or, if you use something like the Bluebird promise library, it has a single function for promisifying any async function that communicates its result via a node.js-style callback passed as the last argument:
var queryAsync = Promise.promisify(db.query, db);

Resources