When a nodejs callback will be called an unknown number of times and you need to do something after the last one - node.js

As I understand it, the node-netstat package parses the output of the netstat command and it calls the callback I supply, once per line of data it parses.
I could do with knowing when it's made its last call, so I know to callback the function that was supplied to my function by elsewhere, but I'm not really sure how to do this..
this.myfunc = function(callback){
netstat(null, function(data){
//netstat will call this function X times. I'd like to accumulate data
});
callback( ..data from netstat.. );
}
If netstat's callback only fired once, with all the data, then I could probably have called callback at the end of function(data), but the multi-calls is confounding that. What do we do in situations like this? (Note also, it's a really prehistoric version of node: 0.10.24)

You can pass an option object to netstat(options, handler) function.
In option object, there is a done field which you can pass a callback function.
More information about option object can be found here

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.

How to read nodejs documentation regarding callback parameters (node v8.x)

I am trying to understand the node.js documentation specifically for the https.get() method. https://nodejs.org/dist/latest-v8.x/docs/api/https.html#https_https_get_options_callback
What is unclear to me is the callback. The example in the document indicates the callback can take a res (response) object as its parameter but I am unsure if this is the only parameter it can take or more importantly where I can find the definition of the res object so I can know what properties and methods I can access on this object.
Is there a straightforward way to identify this?
I have read this thread: Trying to understand nodejs documentation. How to discover callback parameters and the answers seem to suggest that if there is a non-error argument that a callback can take it will be documented, but I am assuming that answer is outdated.
I've run into the same issue with many Node/NPM packages. Documentation sometimes does not describe the parameters well.
So, welcome to JavaScript in 2018! It's gotten a lot better, though, to be honest.
My go-to method is to try the methods and dump the information myself.
Try a console.dir(res) in your callback:
https.get('https://encrypted.google.com/', (res) => {
console.dir(res);
});
Alternatively, you can set a breakpoint in the callback and inspect it yourself. You can then probe the arguments object* to see what else, if anything, was passed as an argument, or do another console dump:
https.get('https://encrypted.google.com/', function (res) {
console.dir("args:", arguments);
console.dir("res:", res);
});
EDIT: Wait, apparently the arguments variable is not available to arrow functions, fixed the second example.
*From MDN:
The arguments object is not an Array. It is similar to an Array, but
does not have any Array properties except length.
From your link https://nodejs.org/dist/latest-v8.x/docs/api/https.html#https_https_get_options_callback, you can see that it works like the http version :
Like http.get() but for HTTPS.
With http.get() clickable.
On that page (https://nodejs.org/dist/latest-v8.x/docs/api/http.html#http_http_get_options_callback), we can see this :
The callback is invoked with a single argument that is an instance of http.IncomingMessage
With http.IncomingMessage clickable, linking this page :
https://nodejs.org/dist/latest-v8.x/docs/api/http.html#http_class_http_incomingmessage
I agree the Node documentation is not very clear about the callbacks in general, and that is a shame. You can still use IDEs with good intellisense (and JSDoc to identify the type of the function parameters), like VSCode.
Or you can use a debugger, always works :)
Edit: If you want to see all the parameters sent to a function, you can use the spread syntax like this :
function foo(...params) {
// Here params is an array containing all the parameters that were sent to the function
}
If you want the absolute truth, you can look at the implementation. Though that's fairly time consuming.
If you find that the documentation is wrong, or in this case could be improved by adding a sentence about the callback parameter to https.get(), please open an issue, or, better yet, a pull request. This is where the change needs to be made:
https://github.com/nodejs/node/blob/67790962daccb5ff19c977119d7231cbe175c206/doc/api/https.md

Node js - overall structure of a program

Hope you are well.
I need your help to understand how to logically organize a program in Node JS to avoid repetition of code given its asynchronous property (as a beginner ..). Let's take an example to make it easier to explain.
One has some data in a mongo database (let's say a list of name). This list of name can be access thanks to the function readData as below
function readData(criteriaRead,callback) {
mongodb.stuff(..)
callback('data read on mongodb')
}
I have two actions in my program: one is to print out the list of name, the other is to check if a name is in the list.
For the first case, it's simple, I just need to have a function like this
function printout(data) {console.log(data)}
and to do this
readData(criteriaRead,printout)
In the second case, let's say I have a function like this
checkIfInIt(array,dataToCheck) {//stuff to check console.log(results)}
Now, I have an issue because if I doreadData(criteriaRead,checkIfInIt) it won't work as checkIfInIt requires two parameters.
I would need a function like this
function readDataBis(criteriaRead,dataToCheck,callback) {
mongodb.stuff(..)
callback('data read on Mongodb','dataToCheck')
}
and then readDataBis(criteriaRead,dataToCheck,checkIfInIt) would work but I have a huge repetition in my code.
How to avoid that?
There are several solutions for this type of issue, but here's an easy one for your case
Declare your function with the three parameters as such
function readData(callback, criteriaRead, dataToCheck) { ...
Inside, check if dataToCheck is undefined, and continue with the flow of the second function you had if that's the case. (Otherwise just do the read function)
Call them like so
readData(callback, criteriaRead); // Third parameter missing, will be undefined
readData(callback, criteriaRead, dataToCheck);
You could also pass in an object for your parameters like this, if it would make it simpler
function readData(callback, params) { ...
And call like this
readData(callback, { criteriaRead: criteriaRead, dataToCheck: dataToCheck });

nodeJS callback error parameter

I'm learning node now and I'm confused about the err parameter.
I thought it's supposed to be the first argument of a callback function but I don't see it in many call back functions. Can anyone explain it to me? Thanks!
There's many different kinds of functions and callback functions in particular. The Node.js standard for callback functions is those of the form:
function(err, arg1, arg2, ...)
Where arg1 and so forth are only present if relevant but the err argument is always first. This is the reverse of a lot of historical JavaScript code where errors would be the last argument.
The Node.js method of forcing the error as the first argument even if there's no error makes ignoring errors harder, you rarely forget to declare that argument, and makes their location predictable.
Now this only applies in the case of a general-purpose callback. That is, there are occasions where calling a function will trigger a singular callback at some point in the future. You'll see them used like this:
doStuff(function(err, successValue) { ... });
There's also the style popularized by jQuery where one or more of your callbacks will be triggered depending on the outcome of the operation:
doStuff({
success: function(successValue) { ... },
error: function(err) { ... },
timeout: function() { ... }
});
Note that in this case you may have both the error and timeout callbacks being fired. You're not obligated to populate all of these, either.
The downside to this approach is the unpredictability of which ones get called and the risk of handling something twice inadvertently.
The error parameter is usually for asynchronous code.
node errors
Most asynchronous methods that accept a callback function will accept an Error object passed as the first argument to that function. If that first argument is not null and is an instance of Error, then an error occurred that should be handled.
app.get() sends get request and return an error like a 404
and you could do something like this res.status(404).render( in app.get()
Express error handling
error-handling functions have four arguments instead of three: (err, req, res, next)
The reason why some code uses err as the first parameter is because some code like fs.readFileis programmed to check if there was an error and to handle it. The author of the API specifically wrote code to check the first argument for an error and handle it.
That's why it is available to you for some methods an unavailable for other methods.
First: a callback is just a function. Different callbacks serve different purposes.
In general, a function that performs an asynchronous action and should "return" a value gets passed a callback function that will take (at least) two arguments: the first is used to pass errors (if any), the second (and following) are used to pass the value(s) that should be returned to the caller.
You noticed that net.createServer() will also take a callback function, but that function only has one argument.
That's because, in this case, the callback isn't used to pass errors and/or values. Instead, it's a function that gets called when a new connection is made to the server.
It's really a bit of a shortcut. This code:
var server = net.createServer(function(connection) {
...
});
Is short for this code:
var server = net.createServer();
server.on('connection', function(connection) {
...
});

node.js fibers with pg/postgres

I've been trying to figure out how to use node-fibers to make my database code less messy in node.js, but I can't get it to work. I boiled the code down to this as a minimum test case:
var Future = require('fibers/future');
var pg=require('pg');
var connstr = "pg://not_the_real_user:or_password#localhost/db";
var pconnect = Future.wrap(pg.connect);
Fiber(function() {
var client = pconnect(connstr).wait();
console.log("called function");
}).run();
If I leave it as is, I get the following error:
pgfuture.js:10
}).run();
^
TypeError: undefined is not a function
at Object.PG.connect.pools.(anonymous function).genericPool.Pool.create (/home/erik/code/treehouse-node/node_modules/pg/lib/index.js:49:20)
at dispense (/home/erik/code/treehouse-node/node_modules/pg/node_modules/generic-pool/lib/generic-pool.js:223:17)
at Object.exports.Pool.me.acquire (/home/erik/code/treehouse-node/node_modules/pg/node_modules/generic-pool/lib/generic-pool.js:267:5)
at PG.connect (/home/erik/code/treehouse-node/node_modules/pg/lib/index.js:75:15)
at Future.wrap (/home/erik/code/treehouse-node/node_modules/fibers/future.js:30:6)
at /home/erik/code/treehouse-node/pgfuture.js:8:18
However, if I comment out the line that calls pconnect, I get the "called function" message on the console and no errors. The example on the github page has an almost identical structure, and it does work correctly on my system, but I'm stumped as to what I'm doing wrong here.
Edit: Additional details
I've managed to get the code to run after a fashion in two different ways that seem unrelated, but both have the same behavior. After the function finishes, node just hangs and I have to kill it with ctrl-c. Here are the two things I've done to get that result:
1) Wrap pg.connect in an anonymous function, and then wrap THAT with Future:
pconnect = Future.wrap(function(err,cb){pg.connect(err,cb);});
2) This one is a real mystery, but it appears to have the same result. Inside the fiber, I just directly call pg.connect before the call to pconnect, and everything seems to work out.
// add this line before call to pconnect
pg.connect(connstr, function(e,c){console.log("connected.");});
// and now the original call to pconnect
var client = pconnect(connstr).wait();
I can imagine a circumstance in which (1) would make sense if, for example, the pg.connect function has other optional arguments that are somehow interfering with the expected layout of the Future.wrap call. Another possibility is that an object is going out of scope and the "this" reference is undefined when the actual call to pconnect is made. I'm at a loss to understand why (2) has any effect though.
Edit: partial answer
Okay, so I answered at least part of the question. The thought I had about object scope turned out to be correct, and by using the bind() function I was able to eliminate the extra layer of callback wrapping:
var pconnect = Future.wrap(pg.connect.bind(pg));
It still hangs at the end of the execution for unknown reasons though.
Are you disconnecting from database at the end of execution?
If not, it prevents node.js program from exiting.
Adding another code of my own which leaks.
#Almad I'm disconnecting here with the provided callback, but still hangs:
var future = Future.task(function() {
var ret = Future.wrap (pg.connect.bind(pg), "array") (conString).wait ();
ret[1]();
}).detach();

Resources