Bluebird promise without a then - node.js

The use case is: I have an event handler that does some processing. It calls a function which returns a promise. I need a guarantee that the function eventually completes or fails, however, I do not need to do any additional processing afterwards. This appears to work but it looks like bad practice:
function onMyEvent() {
return promisifiedFunction()
.catch( //log error );
}
function someFunction() {
emit(‘myevent’);
}
Is this bad practice to have catch without then? It seems to work fine.
I did not think I needed a return either as I could fire-and-forget but I think it's needed if I want to catch the error

With a promise, using .then or .catch runs the promise. Or at least starts running it. A .catch function is just a different path for the Promise, namely when an exception occurs.
If you run a promise without a .then, the promise will resolve silently and could still enter .catch functions.
If you run a promise without a .catch, all .then functions still work/chain, and any exceptions will throw.
What you are doing is OK, and you may not even need the return statement, if you do not care about the result or are not chaining the promise.

Related

Adding a value from Mongoose DB into a variable in Node.js

I am still quite new to Node.js and can't seem to find anything to help me around this.
I am having an issue of getting the query from my last record and adding it to my variable.
If I do it like below: -
let lastRecord = Application.find().sort({$natural:-1}).limit(1).then((result) => { result });
Then I get the value of the variable showing in console.log as : -
Promise { <pending> }
What would I need to do to output this correctly to my full data?
Here is it fixed:
Application.findOne().sort({$natural:-1}).exec().then((lastRecord) => {
console.log(lastRecord); // "lastRecord" is the result. You must use it here.
}, (err) => {
console.log(err); // This only runs if there was an error. "err" contains the data about the error.
});
Several things:
You are only getting one record, not many records, so you just use findOne instead of find. As a result you also don't need limit(1) anymore.
You need to call .exec() to actually run the query.
The result is returned to you inside the callback function, it must be used here.
exec() returns a Promise. A promise in JavaScript is basically just a container that holds a task that will be completed at some point in the future. It has the method then, which allows you to bind functions for it to call when it is complete.
Any time you go out to another server to get some data using JavaScript, the code does not stop and wait for the data. It actually continues executing onward without waiting. This is called "asynchronisity". Then it comes back to run the functions given by then when the data comes back.
Asynchronous is simply a word used to describe a function that will BEGIN executing when you call it, but the code will continue running onward without waiting for it to complete. This is why we need to provide some kind of function for it to come back and execute later when the data is back. This is called a "callback function".
This is a lot to explain from here, but please go do some research on JavaScript Promises and asynchronisity and this will make a lot more sense.
Edit:
If this is inside a function you can do this:
async function someFunc() {
let lastRecord = await Application.findOne().sort({$natural:-1}).exec();
}
Note the word async before the function. This must me there in order for await to work. However this method is a bit tricky to understand if you don't understand promises already. I'd recommend you start with my first suggestion and work your way up to the async/await syntax once you fully understand promises.
Instead of using .then(), you'll want to await the record. For example:
let lastRecord = await Application.find().sort({$natural:-1}).limit(1);
You can learn more about awaiting promises in the MDN entry for await, but the basics are that to use a response from a promise, you either use await or you put your logic into the .then statement.

correct place to call process.exit() in promise chain

Having problems understanding interaction of node processes and promise chains:
doSomethingAsync()
.then()
.then()
.catch()
.finally();
The finally was introduced to close db connections opened inside doSomethingAsync().
Question: In which block does a process.exit(1) on error properly belong?
In the .catch(), since that's where errors will go, or
In the .finally() since it is the last thing that should happen? (But if there is an error and catch() is triggered, do the connections get released)?
nowhere, because node already knows the program failed?
If the goal is to have the application terminate when an error occurs then I wouldn't catch the exception at all
async function doSomething() {
try {
const result = await doSomethingAsync();
// do something with result
} finally {
// do cleanup
}
}
Using async / await syntax will allow the Promise to throw the error and the uncaught exception would terminate the application. The finally block will run regardless of whether an error was thrown or not.
I think in your case process.exit(1) belongs in finally(), because there are database connections to be closed. You would probably want to close them first and then do process.exit(1).
If there was no logic to be performed, I would exit the process in catch().

Can I make Chai's expect.to.not.throw synchronous?

I have a snippet of code that I'm testing in Chai and Pact. It looks something like this:
var myVerify = () => {
provider.verify().then(() => {
console.log('B verified')
done()
})
}
expect(myVerify).to.not.throw()
This works but it's a lot of extra work to go through to make a wrapper function to ensure that I wait on Pact's verify complete's before continuing on with the test. Pact has some internal state that will clear when it's done. If I just call this:
expect(provider.verify()).to.not.throw()
then it will conflict with other tests.
This code seems to work fine for me but it's very messy. Is there a simpler way to accomplish this?
I wouldn't recommend this method since if an error did in fact occur, it would never be caught anyways because promises don't "throw errors", they simply reject the promise, which you can catch using .catch or being the second parameter of the .then.
There are 2 ways of doing what you want:
Just with Mocha:
return provider.verify().then(() => {
console.log('B verified');
done();
}, () => throw new Error("B verification failed"));
In this simple example, we're not using chai to verify anything since you're not actually verifying data output of the verify, you're just checking to see if the promise was a success, if not, throw an error which will fail your tests. Mocha, by default, understands promises as long as they're returned as part of the test.
However, this method means that the wrapping it function needs to inject the done parameter, which I'm not a fan of. What I am a fan of is using:
Chai with Chai as Promised:
You need to set up Chai as Promised using
chai.use(require("chai-as-promised))
then in your tests, simply do:
return expect(provider.verify()).to.eventually.be.fulfilled;
This test will wait for the promise to return, and chai will validate that it is, in fact, fulfilled and not rejected. I find this syntax to be much simpler to use and makes writing tests simpler. You can also have multiple expects with the same promise, using Promises.all:
var verify = provider.verify();
return Promises.all(
expect(verify).to.eventually.be.fulfilled,
expect(verify).to.eventually.be.true,
);

using promises in node.js to create and compare two arrays

I needed to compare two arrays the first one a couple of filenames from a database, the second one a list of files I already downloaded to my client. The Idea was to load whatever files are missing on the client.
As the reading via fswas two slow, I tried using Promises to wait for one function to finish before the next starts. But somehow I got lost...
My code so far:
let filesIneed = [];
let filesIhave = [];
let filesToFetch = [];
getLocalFiles().then(getFilesIneed).then(getfilesToRetreive);
function getLocalFiles() {
fs.readdir(localPath, (err, files) => {
files.forEach(file => {
filesIhave.push(file)
});
})
return Promise.all(filesIhave);
}
function getFilesIneed () {
for (let x of docs) {//this is my JSON
filesIneed.push(y.NameOfFileIShouldHave);
}
}
return Promise.all(filesIneed);
}
function getfilesToRetreive() {
filesToFetch = _.difference(filesIneed, filesIhave);
return Promise.all(filesToFetch);
}
console.log(filesToFetch);
I do get the first and second array ("filesIneed" and "filesIhave"), but difference is always empty. So maybe I just mangled up the Promises, as this concept is completely new to me and I'm aware I only understood half of it.
This is completely wrong. You cannot run Promise.all on an array of filenames. You can only run it on an array of promises.
There is also no need to push every element of an array one at a time to an empty array just to return that array when you already have that array in the first place.
You cannot use promises to compare two arrays. You can use lodash to compare two arrays in a then handler of a promise, that resolves to an array.
If you want to get a promise of file names from the fs.readdir then use one of the following modules:
https://www.npmjs.com/package/mz
http://bluebirdjs.com/docs/api/promise.promisifyall.html
https://www.npmjs.com/package/fs-promise
https://www.npmjs.com/package/fs-promised
Also don't use global variables for everything because you will have problems with any concurrency.
Also, read about promises. Without understanding how promises work you will not be able to guess a correct way of using them. Even looking at some working code examples can help a lot and there are a lot of questions and answers on stack Overflow about promises:
promise call separate from promise-resolution
Q Promise delay
Return Promise result instead of Promise
Exporting module from promise result
What is wrong with promise resolving?
Return value in function from a promise block
How can i return status inside the promise?
Should I refrain from handling Promise rejection asynchronously?
Is the deferred/promise concept in JavaScript a new one or is it a traditional part of functional programming?
How can I chain these functions together with promises?
Promise.all in JavaScript: How to get resolve value for all promises?
Why Promise.all is undefined
function will return null from javascript post/get
Use cancel() inside a then-chain created by promisifyAll
Why is it possible to pass in a non-function parameter to Promise.then() without causing an error?
Implement promises pattern
Promises and performance
Trouble scraping two URLs with promises
http.request not returning data even after specifying return on the 'end' event
async.each not iterating when using promises
jQuery jqXHR - cancel chained calls, trigger error chain
Correct way of handling promisses and server response
Return a value from a function call before completing all operations within the function itself?
Resolving a setTimeout inside API endpoint
Async wait for a function
JavaScript function that returns AJAX call data
try/catch blocks with async/await
jQuery Deferred not calling the resolve/done callbacks in order
Returning data from ajax results in strange object
javascript - Why is there a spec for sync and async modules?
Return data after ajax call success

nodejs async.forEach callback was already called

I'm using the async library to help me with my control flow. I have a collection over which I want to iterate, for each element execute 1 asynchronous task and when all are done, call the callback.
I've decided to use an async.forEach loop, on each loop I call my asynchronous task but I get an error: callback was already called, but shouldn't the callback be called only when all callbacks are called? And I even wanted to understand properly how to handle errors, it is highly probable that some task will fail and others will succeed, I don't need to know which elements fail, but I would like, how can I do this?
This is my code:
async.forEach(fonts, function(font, callback) {
ftpm_module.installOsFont(font, callback);
}, function() {
console.log("finished");
});
EDIT: the error occurs only if I pass 2 or more fonts.

Resources