Skip to content

Beginner · Node.js and Express · topic 12 of 54 · 25 min

Node.js: JavaScript on the server

Explanation

Node.js lets you run JavaScript on a computer or server, not only inside a web browser. It is fast at jobs that wait a lot, like reading a database or calling another service, because it does not sit idle while it waits. You install it once, run files with the node command, and add ready-made code with npm.

JavaScript outside the browser

For many years JavaScript could only run inside a web browser. In 2009 Node.js changed that. Node.js is a runtime: a program that runs JavaScript code directly on a computer, with no browser and no web page.

Node.js uses V8, the same JavaScript engine that runs inside Google Chrome. An engine is the part that reads your code and turns it into instructions the computer understands. Node.js adds extra powers that a browser does not give you: reading and writing files, opening network connections, and starting a web server.

Install it and run your first file

  1. Open nodejs.org and download the LTS version. LTS means Long Term Support: the stable version that gets fixes for years. Pick it, not the newest "Current" one.
  2. Open a terminal and type node --version. If you see a number like v22.11.0, Node.js is installed.
  3. Make a file called hello.js with one line: console.log("Namaste from Node!").
  4. In the terminal, in the same folder, type node hello.js. The message prints in the terminal.
bash
node --version
node hello.js

mkdir my-api
cd my-api
npm init -y
npm install express
Terminal commands: check Node, run a file, start a project and add a package.

npm and package.json

npm is the Node Package Manager. A package is code that someone else wrote and shared, like Express for building web servers. npm init -y creates a file called package.json. This file is the ID card of your project: its name, the packages it needs (called dependencies) and short commands called scripts.

json
{
  "name": "my-api",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node src/server.js",
    "dev": "node --watch src/server.js"
  },
  "dependencies": {
    "express": "^5.1.0"
  }
}
A small package.json. "type": "module" lets you use import and export.
javascript
// file: src/gst.js
export function addGst(price) {
  return Math.round(price * 1.18);
}

// file: src/server.js
import { addGst } from './gst.js';
console.log(addGst(1000)); // 1180
Two files shown together as an example: a module exports a function and another file imports it (runs on a server with Node.js).

The event loop: one waiter, many tables

Think of it like this: Think of one waiter in a busy dhaba. He takes the order at table 1 and gives it to the kitchen. He does not stand in the kitchen waiting for the dal to cook. He goes to table 2, then table 3. When the kitchen rings the bell, he carries the food out. One waiter serves many tables because he never waits doing nothing. Node.js works the same way.

Node.js runs your JavaScript on one main thread (one worker). Slow jobs like reading a database, a file or another website are called I/O (input and output). Node.js starts the I/O job and moves on to other requests. This is called non-blocking I/O. When the job finishes, the event loop picks up the result and runs the code that was waiting for it.

Promises and async/await

A Promise is an object that stands for a result that will arrive later, like a token number at a bank counter. An async function always returns a Promise. Inside it, the word await pauses only that function until the Promise is ready, while Node.js keeps serving everyone else. Promise.all starts several jobs at the same time and waits for all of them.

javascript
function findStudent(id) {
  return new Promise((resolve) => setTimeout(() => resolve({ id, name: 'Meera' }), 100));
}
function findMarks(id) {
  return new Promise((resolve) => setTimeout(() => resolve([78, 85, 91]), 100));
}

async function main() {
  const [student, marks] = await Promise.all([findStudent(7), findMarks(7)]);
  console.log(student.name, 'scored', marks);
}

main();
Two fake slow database calls run at the same time; this prints: Meera scored [ 78, 85, 91 ].
Tip: When two calls do not depend on each other, start them together with Promise.all. Two 100 ms calls then take about 100 ms in total, not 200 ms.
Careful: Forgetting await is the most common beginner mistake. Without it you get a Promise object (printed as Promise { <pending> }) instead of the data, and your code carries on before the data has arrived.

Watch the lesson

Node.js: JavaScript on the server · 1/7

Node.js: JavaScript on the server

Today we take JavaScript out of the browser and run it on a server, with Node.js.

Prefer a video by a teacher? Find free videos on “node.js tutorial for beginners event loop async await” on YouTube ↗

In real life: A college results website on results day

On results day, thousands of students open the results page at the same moment. Each request needs a database lookup that takes, say, 50 milliseconds. A server that waited for each lookup before starting the next would build a long queue. A Node.js server starts every lookup, keeps accepting new students while the database works, and sends each result the moment it is ready. One small server can handle many students this way.

javascript
async function getResult(rollNo) {
  const [student, marks] = await Promise.all([
    db.findStudent(rollNo),
    db.findMarks(rollNo),
  ]);
  return { name: student.name, total: marks.reduce((a, b) => a + b, 0) };
}
Runs on a server with Node.js: both lookups start together.

Practice (0/3 done)

Task 1 · Code · Javascript

getFee(name) pretends to be a slow database: it returns a Promise with the fee of a student. Write an async function totalFee(nameA, nameB) that gets both fees and returns their sum. Bonus: start both calls together with Promise.all.

Task 2 · Code · Javascript

A shop app shows a dashboard. Three fake database calls are given: findUser(id), findOrders(id) and findAlerts(id); each one is slow. Write an async function getDashboard(id) that loads all three AT THE SAME TIME with Promise.all and returns { name, orderCount, unread }, where unread is the number of alerts with read === false. If findUser gives null (no such user), return null. The fake database counts how many calls are running at the same moment, and the test checks that all three ran together.

Task 3 · Practice

Set up Node.js on your own computer. Install the LTS version, make a folder called my-api, create a project with npm and run a small file that prints your name and the total of three fees.

Quick quiz

Question 1

1.What is Node.js?

Question 2

2.Which Node.js version should a beginner install?

Question 3

3.What does package.json hold?

Question 4

4.Why can one Node.js process serve many users at once?

Question 5

5.You wrote const user = findUser(1); without await. What is in user?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Handling errors well