What is Node and why to use it?
What is Node? Node.js is a JS runtime built on top of Google’s opensource V8 Js Engine. Node helps us to run JS outside the browser. It acts like a container to run JS code. V8 engine executes the JS code.
Why Node? With help of Node, we can use JS on server-side of web development. We can build fast, highly scalable applications.
Pros
- Single threaded, based on event driven, non blocking I/O model.
- Perfect for building fast and scalable data-intensive apps
- Eg: Building an API with DB, preferably NoSQL DB.
- Data streaming apps (Youtube or Netflix), Real time chat apps, Server side webapps(Entire content generated on server)
- JS across entire stack: faster and efficient development.
- NPM : huge lib of open-sourcepackages available for free.
- Very active dev community.
When to not use Node?
- Applications with heavy server-side processing (CPU-intensive)
- Image manipulation, Video compression, file compression etc. (Use python or Ruby on rails or PHP for things like this)
REPL
1node
2# acts like a console
3> greet='क्या हाल है?'
4'क्या हाल है?'
5> 7+3
610
7> !0
8true
9> +'7'
107
11> 3*8
1224
13> _+15 # _ adds 15 to previous value
1439
15> _-30 #subtracts 30 from previous value
169
17> .exit or #ctrl + D
Trick: By hitting
tab
in node repl, you can see all global vars available.String.
+tab
-> lists all string methods available
Intro to Node Modules
With Node we can do all sorts of amazing things that we cant with browser, like accessing file system. In order to do that we need to use node modules. All kinds of additional functionality is stored in modules.
How to use modules? Require them in your code and store them in a variable
1const fs = require("fs"); //returns an object with lots of fns which we can later use
- Check out other modules from Official Docs
fs
module
reading and writing files
readFileSync()
:
- Sync version of file Reading
- Takes two args : (filePath, charEncoding)
1const fs = require("fs");
2//reads data from file and encodes in readable format
3const textIn = fs.readFileSync("./txt/input.txt", "utf-8"); // if we dont specify encoding, we get buffer as output
4console.log(textIn);
writeFileSync()
:
- Sync version of file writing
- Takes two args : (filePath, textToOutput)
1const textOut = `This is what we know about : ${textIn}.\nCreated on ${Date.now()}`;
2fs.writeFileSync("./txt/output.txt", textOut);
3console.log("File written");
Blocking and Non-blocking async nature of Node
- The previous written code is synchronous way (each statement is processed one after the other). Each line of code depends on prev line’s execution. This behavour of Synchronous code is also called Blocking code.
- Async code is non-blocking code. We upload heavy work to run in background. Once that work is done A Callback which we registered before is called to handle the result. In the mean time rest of code will be executing, without being blocked by heavy task(running in bg). We need to make our code non-blocking
Async version of previous code …
1fs.readFile("./txt/input.txt", "utf-8", (err, data) => {
2 if (err) throw new Error();
3 console.log(data);
4});
5console.log("reading file...");
Why does it have to be this way? : Node’s process(where our app is running) is a single threaded (A thread is set of instructions that runs on CPU.) For each app there is only one thread. All users accessing your application use the same thread. Whenever they are interacting with your application the code for each user will run on same thread at same place. When one user blocks the code with sync code all have to wait for that execution to complete.
Note: When we use callbacks in our code, it doesn’t automatially make it asynchronous. Passing functions as args is quite common in JS, so that doesn’t make them async automatically. It only works this way for some functions in Node API. One such example is
readFile()
function.While writing async code, make sure you dont get into “Callback hell”. Use ES6->Promises or ES8->Async/Await to escape callback hell.
Reading and Writing files Asynchronously (Non-blocking way)
readFile()
:
- file-encoding is optional. Better to have it
- How this works? node will read our file first in the bg, as soon as it is ready it will start the cb fn we specified
1fs.readFile("./txt/start.txt", "utf-8",
2(err, data) => {
3 console.log(data)
4}
5console.log("will read first")
6//output:
7// will read file
8//text in start.txt
- Note : callback function will run only when reading the file is done
1fs.readFile("./txt/start.txt", "utf-8", (err, data1) => {
2 fs.readFile(`./txt/${data1}.txt`, "utf-8", (err, data2) => {
3 //2nd readFile depends on 1st one coz we are using data of file1 as the name of file2
4 console.log(data2);
5 fs.readFile(`./txt/append.txt`, "utf-8", (err, data3) => {
6 console.log(data3);
7 }
8 });
9});
10console.log("will read file!");
11//output:
12//will read file
13//output of data2
14//output of data 3
writeFile()
:
- Args: where to write, what to write, encoding, callback
1fs.readFile("./txt/start.txt", "utf-8", (err, data1) => {
2 if(err) return console.log(`ERROR!! ${err} 😥`);
3 fs.readFile(`./txt/${data1}.txt`, "utf-8", (err, data2) => {
4 if(err) return console.log(`ERROR!! ${err} 😥`);
5 console.log(data2);
6 fs.readFile(`./txt/append.txt`, "utf-8", (err, data3) => {
7 if(err) return console.log(`ERROR!! ${err} 😥`);
8 console.log(data3);
9 fs.writeFile(`./txt/final.txt`, `${data2}\n${data3}`, "utf-8",
10 (err) => { //no data to read, so only one arg: err
11 console.log('file has been written 😁')
12 })
13 }
14 });
15});
16console.log("will read file!");
17//output:
18// will read file
19//output of data2
20//output of data3
21//file has been written 😁
This type of code is an example of callback hell.