Node - console.log + return values - node.js

I'm just getting started in programming and am using VSC and installed Node and am using it to run my files. My console.logs works, but I can't get return values when I invoke functions. What am I doing wrong?

Node.js is asynchronous. 99% of all functions you write are going to be "non-blocking". If you don't quite understand what that is, I highly suggest you google up on the node.js event loop, and what it means to be "asynchronous".
Once you figure that out, start using the async/await syntax, or "promise" syntax.
Edit:
I see you posted more information. Based on what you're doing, it actually has nothing to do with being asynchronous.
The problem is that you're just returning a string value of hihihihihi... and that's it. You don't print it out anywhere. You need to wrap your call to function a() inside console.log(). So like: console.log(a());

Related

Ensure a Callback is Complete in Mongo Node Driver

I am a bit new to JavaScript web dev, and so am still getting my head around the flow of asynchronous functions, which can be a bit unexpected to the uninitiated. In my particular use case, I want execute a routine on the list of available databases before moving into the main code. Specifically, in order to ensure that a test environment is always properly initialized, I am dropping a database if it already exists, and then building it from configuration files.
The basic flow I have looks like this:
let dbAdmin = client.db("admin").admin();
dbAdmin.listDatabases(function(err, dbs){/*Loop through DBs and drop relevant one if present.*/});
return await buildRelevantDB();
By peppering some console.log() items throughout, I have determined that the listDatabases() call basically puts the callback into a queue of sorts. I actually enter buildRelevantDB() before entering the callback passed to listDatabases. In this particular example, it seems to work anyway, I think because the call that reads the configuration file is also asynchronous and so puts items into the same queue but later, but I find this to be brittle and sloppy. There must be some way to ensure that the listDatabases portion resolves before moving forward.
The closest solution I found is here, but I still don't know how to get the callback I pass to listDatabases to be like a then as in that solution.
Mixing callbacks and promises is a bit more advanced technique, so if you are new to javascript try to avoid it. In fact, try to avoid it even if you already learned everything and became a js ninja.
Dcumentation for listDatabases says it is async, so you can just await it without messing up with callbacks:
const dbs = await dbAdmin.listDatabases();
/*Loop through DBs and drop relevant one if present.*/
The next thing, there is no need to await before return. If you can await within a function, it is async and returns a promise anyway, so just return the promise from buildRelevantDB:
return buildRelevantDB();
Finally, you can drop database directly. No need to iterate over all databases to pick one you want to drop:
await client.db(<db name to drop>).dropDatabase();

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.

What is the proper way to return a JSON object to Alexa Smart Home or end AWS Lambda in NodeJS?

I have seen three ways to return a JSON object or end a Lambda function. My trigger is Smart Home Alexa.
I am using now is context.succeed(response_JSON);This one works for me. Even if this instructions is inside a nested function. The whole Lambda ends and return the response_JSON to Smart Home Alexa.
I have seen in other blogs that say callback(response_error,response_JSON). This one did not work for me. It did not return anything to Smart Home.
Others just uses the return response_JSON. I have not used this one.
I am using now is context.succeed(response_JSON);This one works for me. Even if this instructions is inside a nested function. The whole Lambda ends and return the response_JSON to Smart Home Alexa.
context.succeed()/fail() causes the Lambda function to terminate immediately. However, I have not seen this documented in the context object docs, so it may get deprecated in later Node versions (?).
I have seen in other blogs that say callback(response_error,response_JSON). This one did not work for me. It did not return anything to Smart Home.
This one probably doesn't work for you because by default Node.js waits for the event loop to be empty before executing the callback statement. This may be due to open network/database connection. As per the doc, set the context.callbackWaitsForEmptyEventLoop variable to false to send the response right away.
Others just uses the return response_JSON. I have not used this one.
This should be used with async handlers. Read more about async and non-async handlers here: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html

How do you return a MySQL query result from a node REST API

The MySQL JavaScript api is asynchronous.
If I try to write the filling REST Endpoint it fails as the call to MySQL is asynchronous.
#endpoint
String getSometing(){
RetVal = MySQL.asynchApiQuery(“someSql”)
return RetVal;
}
It will fail as RetVal will not be populated when the function returns.
I’ve spoken to a number of people who rave about JavaScripts asynchronous capabilities yet they have been unable to solve this simple synchronous problem
I’m hoping for a simple answer but so far all I’ve got is observable,promise, subscribe, continuation all of which cannot return the query as a promise simply creates a new thread that cannot be associated with the invoked of the REST api.
Any answer to this should return RetVal and not simply print it.
Look forward to a simple answer.
It's asynchronous but it has something named "callback functions". You can use them to decide what's going to happen with data after a mysql query
Example:
db.query("sqlquery",(err,data)=>{console.log(data)})

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

Resources