Hello World

Running scripts, understanding the event loop, and working with asynchronous code in Node.js

What is Node.js?

Node.js is a JavaScript runtime — it lets you run JavaScript code outside of a web browser. It uses the same V8 engine that powers Google Chrome.

Your First Node.js Script

Create a file called hello.js:

// hello.js - Run with: node hello.js const school = 'UCSD'; const course = 'CSE 135'; const year = new Date().getFullYear(); // Template strings (ES6) work naturally console.log(`Welcome to ${course} at ${school}, ${year}!`); // Unlike PHP, this script runs once and exits // There's no HTTP request triggering it - we just ran a file

Run it from the terminal:

$ node hello.js Welcome to CSE 135 at UCSD, 2026!

That's it. Node.js executed your JavaScript file, printed output, and exited.

Running Node.js Interactively

Beyond running files with node filename.js, there are other ways to execute Node.js code:

The REPL (Read-Eval-Print Loop)

Run node with no arguments to enter an interactive shell:

$ node Welcome to Node.js v22.x.x > 2 + 2 4 > const x = 'hello' undefined > x.toUpperCase() 'HELLO' > .exit

Loading Files in the REPL

Use .load to execute a file within the REPL, keeping its variables available:

$ node > .load hello.js Welcome to CSE 135 at UCSD, 2026! > school 'UCSD' > course 'CSE 135'

This is useful for testing and exploring your code interactively.

Unix Input Redirection

You can pipe a file into Node.js using Unix shell redirection:

$ node < hello.js Welcome to CSE 135 at UCSD, 2026!

This is equivalent to node hello.js but uses stdin. Useful in shell scripts or when combining with other Unix tools.

ES6+ Features Just Work

Since Node.js uses V8, all modern JavaScript features are available:

// Arrow functions const greet = (name) => `Hello, ${name}!`; // Destructuring const { method, url } = request; // Spread operator const merged = { ...defaults, ...options }; // async/await const data = await fetch(url); // Classes class Server { constructor(port) { this.port = port; } }

The Event Loop

Here's the most important concept in Node.js: the event loop.

Node.js is single-threaded, but it handles many concurrent operations using an event loop. When you do something that takes time (reading a file, making an HTTP request), Node doesn't wait. It schedules the work and continues running other code.

// async-demo.js - Demonstrates the event loop console.log('1. Script starts'); // setTimeout schedules work for later setTimeout(() => { console.log('3. This runs after 2 seconds'); }, 2000); console.log('2. Script continues immediately'); // Output order: // 1. Script starts // 2. Script continues immediately // (2 seconds pass) // 3. This runs after 2 seconds

Run it:

$ node async-demo.js 1. Script starts 2. Script continues immediately (2 seconds pass) 3. This runs after 2 seconds

Notice that "Script continues" prints BEFORE the setTimeout callback. Node doesn't block waiting for the timer.

Why This Matters for Web Servers

This non-blocking behavior is why Node.js handles many concurrent connections efficiently:

// Conceptual example (not runnable yet) server.on('request', (req, res) => { // Read from database (takes time) database.query('SELECT * FROM users', (err, results) => { // This callback runs when data is ready res.json(results); }); // Node doesn't wait here - it can handle other requests! });

While waiting for the database, Node.js can handle other requests on the same thread. Note that PHP with Apache handles concurrency differently: Apache typically spawns multiple worker processes or threads, so while each PHP script blocks within its own process, the server as a whole still handles concurrent requests. The trade-off is in memory and resource usage per connection.

Async Patterns: Callbacks, Promises, and Async/Await

Node.js has three patterns for handling async operations. Each is syntactically different, but all fundamentally deal with the same challenge: managing chained dependencies where one operation depends on the result of another.

Callbacks

fs.readFile('data.txt', (err, data) => { if (err) throw err; console.log(data); });

Promises

fs.promises.readFile('data.txt') .then(data => console.log(data)) .catch(err => console.error(err));

Async/Await

async function readData() { try { const data = await fs.promises.readFile('data.txt'); console.log(data); } catch (err) { console.error(err); } }

Key Differences from PHP

Aspect PHP Node.js
Execution Per-request (starts, runs, exits) Persistent (runs continuously)
State Resets each request Persists in memory
Concurrency Model Multi-process (Apache spawns workers) Single-threaded event loop
Server Role Runs inside Apache/nginx Creates own HTTP listener
Production Setup Apache handles HTTP directly Usually behind nginx/reverse proxy

Summary

  • Node.js runs JavaScript outside the browser
  • Scripts run with node filename.js, or interactively via the REPL
  • Use .load in the REPL or node < file.js for alternative execution
  • Modern ES6+ features work without transpilation; TypeScript is supported natively in Node 22+
  • The event loop enables non-blocking I/O on a single thread
  • In production, Node.js typically runs behind a reverse proxy