WEEK 10 · ISLAND OF PORTS

Node.js β€” JavaScript as Backend

The same JavaScript you've written all semester β€” now running the server itself. Every server on this page runs live, in a Node emulator built into your browser.

This week Node.js V8 event loop, level 2 npm & package.json http server url Β· fs Β· path MVC

0 Week at a glance

browser JS β†’ Node.js β†’ npm β†’ your first server β†’ MVC. JavaScript takes over the backend.
  • Server-side programming β€” code that runs on the server, hidden from visitors.
  • Node.js β€” Chrome's V8 engine, unplugged from the browser and given server superpowers.
  • Event loop, level 2 β€” Week 9's loop returns, now with the microtask queue.
  • npm β€” the world's biggest code registry, and package.json, your project's manifest.
  • Core modules β€” http, url, fs, path: everything you need for a real server.
  • MVC β€” the architecture that keeps server code from becoming spaghetti.

New this week: the Node emulator. Node code can't normally run in a web page β€” so this island ships a mini Node.js written in JavaScript. Examples marked 🟒 node emulator support require(), a virtual disk, and real servers you can visit with the built-in mini-browser. Everything is editable, as always.

1 Why backends?

Key terms server-side dynamic pages hidden code web hosting
The frontend is the dining room; the backend is the kitchen. Guests never see the kitchen β€” but that's where everything is made.
  • Server-side pages are programs β€” PHP, Java/JSP, Ruby on Rails, ASP.NET, Python, and now JavaScript.
  • They make pages dynamic: different content per user, per time, per context.
  • They talk to other services: databases, e-mail, payment systems.
  • They authenticate users and process form data safely.
  • They give security: server code can never be viewed from a browser.

Prove it β€” what can the visitor actually see?

app.js Β· lives on the server only
// Secrets can live here β€” the browser NEVER receives this file
const API_KEY = "sk-live-9f2…TOP-SECRET";
const db = connect("mongodb://anime-db:27017");

server.get("/anime", (req, res) => {
  const anime = db.query("SELECT * FROM anime");
  res.send(renderPage(anime));   // only the RESULT is sent
});

Performance & compatibility wins

  • Compute once, cache β€” don't repeat heavy work for every visitor.
  • Stronger machines β€” heavy computation runs on server hardware, not a student laptop.
  • Near the data β€” data-intensive work runs next to the database.
  • Compatibility β€” dynamic behaviour even for clients with little or no JS support.

Web hosting β€” where servers live

Hosting = storing files on a server and making them accessible over the internet, securely and stably.

Hosting typeThe idea
SharedMany websites share one machine β€” cheapest, least control.
VPS (virtual private server)One machine sliced into isolated virtual servers.
DedicatedA whole physical machine for you alone.
ManagedSomeone else handles updates, backups and security.
CloudElastic resources across many machines β€” scale up and down on demand.
Choosing one reliability flexibility security price

2 What is Node.js

Key terms runtime environment V8 event-driven non-blocking I/O single-threaded

Node.js = a JavaScript runtime environment, written in C++, that lets JavaScript run in the backend. It interprets and executes JS, and ships a set of libraries (the Node API) for building server programs.

2009 β€” Ryan Dahl, impressed by the speed of Chrome's V8 engine, pulls JavaScript out of the browser. Node.js is born.

The three key features

FeatureMeaning
Event-driven architectureHandles multiple connections using an event loop β€” work happens when events fire.
Non-blocking I/OInput/output (network, files, databases) runs asynchronously β€” waiting costs nothing.
Single-threadedOne thread β€” yet it manages thousands of requests efficiently. Week 9 explained how!

Traditional server vs. Node

Traditional (thread-per-request)Node.js (event loop)
Each request gets…Its own threadA callback in the queue
While waiting for the DB…The thread sits blocked, wasting memoryThe loop serves other requests
10 000 connections10 000 threads 😰Still one thread 😎
WinsSimple mental model, true parallel CPU workScalability, responsiveness, resource efficiency, simpler error handling

Why developers love it

  • Lightweight and fast β€” V8 compiles JS to machine code.
  • One language everywhere β€” JS is the only language that runs both frontend and backend: shared code, shared types, shared libraries.
  • Easy learning curve β€” you already know the language!
  • Ecosystem β€” npm hosts over two million packages.
  • Community-powered β€” cross-platform and multi-purpose.
Built with Node REST APIs real-time chat streaming apps CLI tools microservices IoT

3 One engine, two worlds

Key terms V8 engine DOM APIs Node APIs no document in Node!
Chrome and Node share the same V8 engine β€” they just plug different toolboxes into it.
🌐 Chrome (browser)
V8 engine
parser Β· execution engine Β· garbage collector Β· call stack
+
DOM API implementation
document, window, alert, fetch, events…
🟒 Node.js (server)
V8 engine
the exact same engine!
+
Node API implementation
http, fs, path, os, process…
  • Ask Chrome's V8 to run console.log('V8') β€” works. Ask it for document.querySelector('div') β€” the DOM API answers.
  • Ask Node's V8 to run http.createServer() β€” the Node API answers.
  • Ask Node for document.querySelector('div') β€” ???????? There is no DOM on a server!
no-dom-here.js
// This runs in the NODE EMULATOR β€” there is no web page here.
console.log("Node says hi β€” no browser needed!");

const os = require('os');
console.log("Platform:", os.platform(), "Β· CPU cores:", os.cpus().length);

// Now try the impossible:
document.querySelector("div");   // πŸ’₯ servers have no document!

The sorting game: will it run?

For each snippet, decide: Browser, Node, or Both?
document.querySelector("h1")
const http = require('http')
console.log("hello")
alert("Hi!")
const fs = require('fs')
setTimeout(cb, 1000)
fetch("https://api.github.com")
window.location.href
0 / 8 sorted

4 The event loop, level 2

Key terms call stack task queue micro-task queue priority!
New this week: Promises get a VIP lane. The micro-task queue always beats the task queue.
  • Call stack β€” runs your functions, one at a time (Week 9 recap).
  • Internal implementation β€” the C++ code (browser or Node) behind setTimeout & friends. The host itself is multi-threaded β€” your JS is not.
  • Task queue β€” callbacks from setTimeout, addEventListener… wait here.
  • Micro-task queue β€” Promise callbacks are special: they get their own, higher-priority queue.
  • Event loop β€” when the stack empties, it drains all micro-tasks first, then takes one task.

Watch the VIP lane in action

microtask-demo.js
console.log("Start");setTimeout(() => console.log("Timeout!"), 0);Promise.resolve().then(() => console.log("Promise!"));console.log("End");
Press Play to start the simulation.
πŸ“š Call stack (JS thread)
βš™οΈ Internal implementation
⚑ Micro-task queue (VIP)
⏳ Task queue
πŸ–₯️ Console

Don't believe the simulation? Run the real thing

priority.js Β· predict first, then Run
console.log("Start");

setTimeout(() => console.log("Timeout!"), 0);           // task queue

Promise.resolve().then(() => console.log("Promise!"));  // MICRO-task queue

console.log("End");

Exam favourite: the order is Start β†’ End β†’ Promise! β†’ Timeout! Even at 0 ms, the timeout callback waits in the task queue while the Promise callback cuts the line through the micro-task queue.

Extra practice: jsv9000.app β€” paste any program and step through the loop frame by frame. Edit the code and run it again!

5 Getting Node on your machine

terminal Β· check your install
node -v     // v22.x  β†’ the runtime
npm -v      // 10.x   β†’ the package manager (ships WITH Node)

Installation instructions: the Pre-Lab inside Lab 4 on Brightspace has the full step-by-step guide. Install before the lab β€” it takes five minutes.

Everything on this page runs in the emulator β€” but the lab needs the real thing.

6 Modules & require()

Key terms core modules file-based modules npm modules require()
A module = one file, one job. require() is how files borrow each other's tools.
You writeNode loads
require("fs")A core module (built into Node) β€” or an npm package from node_modules/.
require("./greet")Your file greet.js, from the same directory.
require("../utils/greet")Your file, from the parent directory.
require("/abs/path/greet")Your file, by absolute path.

The core modules toolbox

ModuleJob
fsFile system operations β€” reading & writing files.
httpCreating HTTP servers and handling requests.
pathWorking with file and directory paths.
osSystem information β€” CPU, memory, platform.
eventsEvent-driven programming (EventEmitter).
cryptoEncryption, hashing and security operations.
core-modules.js
const os = require('os');
const path = require('path');

console.log("You are on:", os.platform());
console.log("CPU cores:", os.cpus().length);
console.log("joined path:", path.join("students", "week10", "app.js"));

// The emulator ships core modules only. Try uncommenting:
// require('express');   // β†’ Error: Cannot find module 'express'

User-defined modules β€” your own files

greet.js β€” exports a tool
greet.js
function greet(name) {
  return "Hello, " + name + "!";
}

module.exports = greet;   // make it borrowable
app.js β€” borrows it
app.js
const greet = require("./greet");

console.log(greet("Prof. Abul Qasim"));
// β†’ Hello, Prof. Abul Qasim!

7 npm & package.json

Key terms npm init -y npm install package.json node_modules/ devDependencies
npm = the app store for Node code. package.json = your project's shopping list.
  • npm (Node Package Manager) comes with the Node.js installation.
  • npm install <package> downloads a package into node_modules/ and records it in package.json.
  • Installed packages are used via require() β€” same as core modules.
  • npm install -g nodemon installs globally β€” a command available everywhere (nodemon auto-restarts your server on every save).

The practice terminal β€” set up a real project

The recipe: npm init -y β†’ npm install express β†’ node app.js. Type it (or click the chips) and watch the folder build itself.
student@algonquin: ~/my-first-server
$
my-first-server/
    package.json will appear here after npm init -y

    What is package.json?

    package.json is the configuration file of a Node project: its name, version, scripts, metadata β€” and most importantly its dependencies. Created automatically with npm init -y (-y = "yes to all questions").

    • Running npm install with no arguments installs everything listed in package.json.
    • That's why node_modules/ is never committed to git β€” anyone can rebuild it from package.json.

    dependencies vs. devDependencies

    dependenciesdevDependencies
    Needed…At runtime β€” the app breaks without themOnly while developing
    Examplesexpressnodemon, test runners
    Install flagnpm install express (--save is the default)npm install --save-dev nodemon
    In productionInstalledSkipped β€” smaller, faster deploys

    8 Semantic versioning & the lockfile

    Key terms MAJOR.MINOR.PATCH ^ caret ~ tilde package-lock.json
    4.21.2 = MAJOR.MINOR.PATCH β€” breaking changes . new features . bug fixes.

    The ^ and ~ playground

    package.json says "express": "^4.21.2". Which versions is npm allowed to install? Pick a prefix:

    Memory hook: ~ is a small wiggle (patches only) Β· ^ points up higher (minors too) Β· no prefix = frozen solid. npm's default when you install is ^.

    package-lock.json β€” the exact receipt

    • Generated on npm install β€” catalogs exactly what landed in node_modules/.
    • On the next install, package-lock.json trumps package.json: the locked versions win.
    • Result: your teammate installs the identical versions you have. No "works on my machine".
    Featurepackage.jsonpackage-lock.json
    PurposeProject metadata & dependency rangesLocks exact versions of everything
    VersioningSemantic ranges ("express": "^4.21.2")Exact pins ("version": "4.21.2")
    Created byYou (via npm init, then edited)npm, automatically on install
    Edit by hand?Yes, routinelyNever
    Guarantees stability?No β€” ranges allow updatesYes β€” prevents version drift

    9 Your first server

    Key terms http.createServer req Β· res server.listen(port) res.end() β€” always! status codes
    Lifecycle of a request: browser sends a request β†’ Node runs your callback with (req, res) β†’ you build and send the response.

    http.createServer(callback) creates a web server. The callback receives req (the incoming request β€” URL, method, headers) and res (an object that collects your response). server.listen(port) opens the port and starts accepting visitors.

    Hello, World β€” a real server, right here

    Run it, then visit your own server in the mini-browser that appears. Edit the message and run again!
    hello-server.js
    const http = require('http');
    
    const server = http.createServer(function (req, res) {
      res.writeHead(200, { "Content-Type": "text/plain" });
      res.write("Hello World from my first server!");
      res.end();
    });
    
    server.listen(3000, () => {
      console.log("Server running at http://localhost:3000");
    });

    Spot the bug β€” the original slide version

    This server starts fine… but crashes when someone visits. Run it, visit it, read the error β€” then fix it live.
    buggy-server.js Β· one letter is wrong
    var http = require('http');
    
    var server = http.createServer(function (req, res) {
      res.writeHead(200);
      resp.write('Hello World');   // πŸ› hmm…
      res.end();
    });
    
    server.listen(3000);

    Lesson inside the bug: the callback only runs per request β€” a broken handler starts up fine and explodes on the first visit. Always test by visiting!

    What's inside req?

    inspect-request.js Β· visit different paths and watch the console
    const http = require('http');
    
    const server = http.createServer((req, res) => {
      console.log("method:", req.method);        // 'GET', 'POST', …
      console.log("url:", req.url);              // '/users', '/about?x=1', …
      console.log("host header:", req.headers.host);
      console.log("http version:", req.httpVersion);
      res.end("Request received β€” now check the console output!");
    });
    
    server.listen(3000);

    Building the response

    MethodJob
    res.writeHead(code, headers)Set the status code + headers in one go.
    res.write(chunk)Write a piece of the response body.
    res.end([chunk])Finish the response β€” mandatory! Forget it and the browser waits forever.
    res.json(obj)Send a JSON response (an Express nicety β€” the emulator has it too).
    res.download(path)Send a file back (Express).

    Status codes & MIME types

    FamilyMeaningFamous examples
    1xxInformational100 Continue
    2xxSuccess200 OK, 201 Created
    3xxRedirection301 Moved Permanently, 304 Not Modified
    4xxClient error404 Not Found, 403 Forbidden
    5xxServer error500 Internal Server Error (you met it in the buggy server!)
    Common MIME types text/html application/json application/pdf image/png

    10 The URL module

    Key terms new URL() pathname search searchParams
    A URL is not a string β€” it's six pieces. The URL class cuts it up for you, safely.

    Anatomy of a URL β€” click each piece

    https://www.example.com:8080/products/shoes?color=red&size=10#reviews
    ☝️ Click any coloured piece of the URL to dissect it.

    Properties & searchParams β€” live

    url-anatomy.js
    const { URL } = require('url');
    
    const myUrl = new URL("https://www.example.com:8080/products/shoes?color=red&size=10#reviews");
    
    console.log("protocol:", myUrl.protocol);
    console.log("hostname:", myUrl.hostname);
    console.log("port:", myUrl.port);
    console.log("pathname:", myUrl.pathname);
    console.log("search:", myUrl.search);
    console.log("hash:", myUrl.hash);
    
    // searchParams: get / set / append / delete
    const p = myUrl.searchParams;
    console.log("color =", p.get("color"));
    p.set("size", "11");
    p.append("coupon", "WEEK10");
    console.log("updated URL:", myUrl.href);

    A server that reads the query string

    Run it, then in the mini-browser try: /calendar?month=July&year=2026
    query-server.js
    const http = require('http');
    const { URL } = require('url');
    
    const server = http.createServer(function (req, res) {
      res.writeHead(200, { "Content-Type": "text/html" });
    
      const q = new URL(req.url, "http://" + req.headers.host);
    
      res.write("host = " + req.headers.host);
      res.write("<br>pathname = " + q.pathname);
      res.write("<br>search = " + q.search);
    
      const qdata = q.searchParams;
      res.write("<br><b>Month = " + qdata.get("month") + "</b>");
      res.write("<br><b>Year = " + qdata.get("year") + "</b>");
      res.end();
    });
    
    server.listen(8080, () => console.log("Server running at http://localhost:8080"));

    11 The fs & path modules

    Key terms fs.promises await readFile path.join() cross-platform
    Browsers must never touch your files. Servers live on files. Enter fs β€” and everything you learned in Week 9 pays off.
    • Node supports reading, writing, creating and deleting files.
    • require('fs').promises imports the modern, non-blocking, Promise-based API β€” made for await.
    files.js Β· a virtual disk lives in this page
    const fs = require('fs').promises;   // the Promise-based API
    
    // Week 9 skills, server edition:
    const data = await fs.readFile('example.txt', 'utf8');
    console.log("example.txt says:", data);
    
    await fs.writeFile('notes.txt', 'Node.js writes files!');
    await fs.appendFile('notes.txt', ' And appends too.');
    console.log("notes.txt says:", await fs.readFile('notes.txt', 'utf8'));
    
    console.log("the disk now holds:", await fs.readdir('.'));

    The Week 9 connection: fs.promises methods return Promises β€” so await, try/catch and everything from the Island of Time applies, unchanged.

    path β€” never glue paths by hand

    • Windows uses \, Mac/Linux use / β€” path handles both, cross-platform.
    paths.js
    const path = require('path');
    
    const p = "/students/week10/report.pdf";
    console.log("basename:", path.basename(p));   // file name
    console.log("dirname :", path.dirname(p));    // its directory
    console.log("extname :", path.extname(p));    // file extension
    
    // join: cleans up slashes AND resolves '..' automatically
    console.log("join    :", path.join("students", "week10", "..", "week11", "lab.js"));
    
    // resolve: always returns an ABSOLUTE path
    console.log("resolve :", path.resolve("images", "logo.png"));

    12 Model – View – Controller

    Key terms Model = data + logic View = presentation Controller = the brains separation of concerns
    MVC keeps business logic away from the GUI β€” the design paradigm behind maintainable apps.
    PartRepresentsResponsibilities
    🧠 ModelKnowledgeStores the data + the logic to access and change it. Calculations, data manipulation. Exists independently of how it's displayed.
    🎨 ViewPresentationHow data is shown to the user β€” renders HTML (or JSON, XML…). Receives data from the controller. Presentation logic only.
    🚦 ControllerThe link user ↔ systemThe brains: reads the user's input, validates & sanitizes it, decides how the model changes, and picks which view to render.

    Follow one request through MVC

    πŸ§‘ Browser

    the user

    ⇄
    🚦 Controller

    decides

    ⇄
    🧠 Model

    data + logic

    β‡…
    🎨 View

    renders

    Press the button to send a request through the M-V-C machine.

    Why bother?

    • Separation of concerns β€” data, logic and looks live apart.
    • Data can change independently of its presentation.
    • The same data, different views β€” one model can feed a web page, an app and an API.
    • Easier maintenance and testing β€” each part tests in isolation.
    • Team-friendly β€” coding tasks split cleanly between people.
    • Reusability β€” one model, many views.
    In Node, MVC usually comes via a framework: Express.js β€” that's where our voyage heads next.

    13 Key takeaways

    1. Server-side code is invisible to visitors β€” that's where secrets, databases and authentication live.
    2. Node.js = V8 + Node APIs β€” Chrome's engine, with http/fs/path instead of the DOM. No document on a server!
    3. Node is event-driven, non-blocking, single-threaded β€” one thread serves thousands of connections.
    4. The micro-task queue (Promises) beats the task queue (setTimeout) β€” every time the stack empties.
    5. require() loads core modules ("fs"), your files ("./greet"), or npm packages ("express").
    6. npm init -y creates package.json Β· npm install reads it Β· package-lock.json pins exact versions and wins.
    7. Semver: ^ allows minor + patch, ~ allows patch only, no prefix = exactly that version.
    8. http.createServer((req, res)) + server.listen(port) β€” and always res.end(), or the browser waits forever.
    9. new URL() + searchParams dissect URLs and query strings safely.
    10. MVC: Model = data + logic Β· View = presentation Β· Controller = the brains between them.

    14 Self-check quiz

    No grades, instant feedback. Can you get all eight?

    Q1. What is Node.js?

    Node.js is a runtime environment (written in C++): the same V8 engine as Chrome, paired with the Node APIs (http, fs, path…) instead of the DOM.

    Q2. What does this print, in order?
    console.log("A"); setTimeout(() => console.log("B"), 0); Promise.resolve().then(() => console.log("C")); console.log("D");

    Synchronous code first (A, D). Then the event loop drains the micro-task queue (C) before touching the task queue (B) β€” even at 0 ms.

    Q3. package.json says "express": "^4.21.2". Which version may npm install?

    ^ means "anything β‰₯ 4.21.2 but < 5.0.0" β€” new features and bug fixes yes, breaking changes no. For exact-only you'd write 4.21.2 with no prefix.

    Q4. Both package.json and package-lock.json list express. On npm install, which wins?

    The lockfile "trumps" package.json: everyone on the team installs the identical versions. That's also why you never edit package-lock.json by hand.

    Q5. What's the difference between require("fs") and require("./fs")?

    No prefix = core module or node_modules package. ./ = a file in the same directory, ../ = the parent directory.

    Q6. Which line crashes when run in Node.js?

    Node has no DOM β€” document is not defined on a server. Timers and core modules work fine.

    Q7. Your handler runs res.write("hi") but never calls res.end(). The visitor's browser…

    res.end() is what completes the response. Without it the connection stays open and the browser spins forever (you saw this in the mini-browser's timeout!).

    Q8. In MVC, which part validates the user's input and decides which view to render?

    The Controller reads input, validates & sanitizes it, tells the Model what to change, and picks the View. The Model owns data + business logic; the View only presents.

    15 Reading & practice

    Zybooks β€” Chapter 10 "node.js": sections 10.1 – 10.3. Do the participation activities β€” they mirror this week's lab.

    Challenge: in the hello-server example, make the server answer differently on /about (your name) and / (a welcome) β€” hint: req.url + an if.