2009 Ryan Dahl: Node.js¶
Key Dates¶
- 2008: Google releases Chrome and open-sources V8 JavaScript engine
- Early 2009: Ryan Dahl begins experimenting with server-side JavaScript using V8
- May 27, 2009: First version of Node.js released
- November 8, 2009: Ryan Dahl introduces Node.js at JSConf EU in Berlin (see video, conference page)
Slides¶
Node.js - Original slides from Ryan Dahl’s intro talk
- Who: Ryan Dahl
- Where: JS Conf EU
- When: November 8, 2009
Slide 1: Title¶
node.js
ry@tinyclouds.org
November 8, 2009
Slide 2: Node.js in Brief¶
- Server-side Javascript
- Built on Google’s V8
- Evented, non-blocking I/O. Similar to EventMachine or Twisted.
- CommonJS module system.
- 8000 lines of C/C++, 2000 lines of Javascript, 14 contributors.
Slide 3: The Problem¶
I/O needs to be done differently.
Slide 4: Blocking I/O Example¶
Many web applications have code like this:
var result = db.query("select * from T");
// use result
Slide 5: Waiting¶
In many cases, just waiting for the response.
Slide 6: I/O Latency¶
- L1: 3 cycles
- L2: 14 cycles
- RAM: 250 cycles
- DISK: 41,000,000 cycles
- NETWORK: 240,000,000 cycles
Slide 7: Multitasking Solution¶
Better software can multitask.
Other threads of execution can run while waiting.
Slide 8: Can We Do Better?¶
Is that the best that can be done?
A look at Apache and NGINX.
Slide 9: Apache vs NGINX - Performance¶
concurrency × reqs/sec

http://blog.webfaction.com/a-little-holiday-present
Slide 10: Apache vs NGINX - Memory¶
concurrency × memory

http://blog.webfaction.com/a-little-holiday-present
Slide 11: The Difference¶
Apache vs NGINX
The difference?
- Apache uses one thread per connection.
- NGINX doesn’t use threads. It uses an event loop.
Slide 12: Thread Limitations¶
- Context switching is not free
- Execution stacks take up memory
- For massive concurrency, cannot use an OS thread for each connection.
Slide 13: Green Threads¶
Green threads or coroutines can improve the situation dramatically
BUT there is still machinery involved to create the illusion of holding execution on I/O.
Slide 14: Leaky Abstraction¶
Threaded concurrency is a leaky abstraction.
Slide 15: The Problem with Blocking¶
Code like this:
var result = db.query("select..");
// use result
either blocks the entire process or implies multiple execution stacks.
Slide 16: Non-blocking Solution¶
But a line of code like this:
db.query("select..", function (result) {
// use result
});
allows the program to return to the event loop immediately.
No machinery required.
Slide 17: The Right Way¶
db.query("select..", function (result) {
// use result
});
This is how I/O should be done.
Slide 18: Why Not Everyone?¶
So why isn’t everyone using event loops, callbacks, and non-blocking I/O?
For reasons both cultural and infrastructural.
Slide 19: Cultural Bias - Traditional I/O¶
Cultural Bias
We’re taught I/O with this:
puts("Enter your name: ");
var name = gets();
puts("Name: " + name);
We’re taught to demand input and do nothing until we have it.
Slide 20: Cultural Bias - Callbacks Rejected¶
Cultural Bias
Code like:
puts("Enter your name: ");
gets(function (name) {
puts("Name: " + name);
});
is rejected as too complicated.
Slide 21: Missing Infrastructure - Libraries¶
Missing Infrastructure
So why isn’t everyone using event loops?
Single threaded event loops require I/O to be non-blocking
Most libraries are not.
Slide 22: Missing Infrastructure - Details¶
Missing Infrastructure
- POSIX async file I/O not available.
- Man pages don’t state if a function will access the disk. (e.g getpwuid())
- No closures or anonymous functions in C; makes callbacks difficult.
- Database libraries (e.g. libmysql client) do not provide support for asynchronous queries
- Asynchronous DNS resolution not standard on most systems.
Slide 23: Too Much Infrastructure - Confusion¶
Too Much Infrastructure
EventMachine, Twisted, AnyEvent provide very good event loop platforms.
Easy to create efficient servers.
But users are confused how to combine with other available libraries.
Slide 24: Expert Knowledge Required¶
Too Much Infrastructure
Users still require expert knowledge of event loops, non-blocking I/O.
Slide 25: JavaScript’s Advantages¶
Javascript designed specifically to be used with an event loop:
- Anonymous functions, closures.
- Only one callback at a time.
- I/O through DOM event callbacks.
Slide 26: JavaScript Culture¶
The culture of Javascript is already geared towards evented programming.
Slide 27: The Node.js Project¶
This is the node.js project:
To provide a purely evented, non-blocking infrastructure to script highly concurrent programs.
Slide 28: Design Goals - No Direct I/O¶
Design Goals
- No function should direct perform I/O.
- To receive info from disk, network, or another process there must be a callback.
Slide 29: Design Goals - Low-level¶
Design Goals
- Low-level.
- Stream everything; never force the buffering of data.
- Do not remove functionality present at the POSIX layer. For example, support half-closed TCP connections.
Slide 30: Design Goals - Protocol Support¶
Design Goals
Have built-in support for the most important protocols:
- TCP
- DNS
- HTTP
Slide 31: Design Goals - HTTP Features¶
Design Goals
Support many HTTP features:
- Chunked requests and responses.
- Keep-alive.
- Hang requests for comet applications.
Slide 32: Design Goals - API Familiarity¶
Design Goals
The API should be both familiar to client-side JS programmers and old school UNIX hackers.
Be platform independent.
Slide 33: Usage and Examples¶
Usage and Examples
(using node 0.1.16)
Slide 34: Installation¶
Download, configure, compile, and make install it.
http://nodejs.org/
No dependencies other than Python for the build system. V8 is included in the distribution.
Slide 35: Hello World Example¶
var sys = require("sys");
setTimeout(function () {
sys.puts("world");
}, 2000);
sys.puts("hello");
Slide 36: Auto Exit¶
var sys = require("sys");
setTimeout(function () {
sys.puts("world");
}, 2000);
sys.puts("hello");
Node exits automatically when there is nothing else to do.
Slide 37: Running the Example¶
% node hello_world.js
hello
# 2 seconds later...
% node hello_world.js
hello
world
%
Slide 38: Signal Handling¶
Change the “hello world” program to loop forever, but print an exit message when the user kills it.
We will use the special object process and the "SIGINT" signal.
Slide 39: Signal Handling Code¶
puts = require("sys").puts;
setInterval(function () {
puts("hello");
}, 500);
process.addListener("SIGINT",
function () {
puts("good bye");
process.exit(0)
});
Slide 40: Process Event Listener¶
process.addListener("SIGINT", ...);
The process object emits an event when it receives a signal. Like in the DOM, you need only add a listener to catch them.
Slide 41: Process Object Properties¶
Also:
process.pidprocess.ARGVprocess.ENVprocess.cwd()process.memoryUsage()
Slide 42: Event Emitters¶
Like process, many other objects in Node emit events.
Slide 43: Event Examples¶
- A TCP server emits a
"connection"event each time someone connects. - An HTTP upload emits a
"body"event on each packet.
Slide 44: EventEmitter Base¶
All objects which emit events are instances of process.EventEmitter.
Slide 45: TCP Server Task¶
Write a program which: - starts a TCP server on port 8000 - send the peer a message - close the connection
Slide 46: TCP Server Example¶
var tcp = require("tcp");
var s = tcp.createServer();
s.addListener("connection",
function (c) {
c.send("hello!");
c.close();
});
s.listen(8000);
Slide 47: Testing the Server¶
% node server.js &
[1] 9120
% telnet localhost 8000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello!
Connection closed by foreign host.
%
Slide 48: Simplified Version¶
The "connection" listener can be provided as the first argument to tcp.createServer(), so the program can be simplified:
Slide 49: Simplified TCP Server¶
var tcp = require("tcp");
tcp.createServer(function (c) {
c.send("hello!\n");
c.close();
}).listen(8000);
Slide 50: Non-blocking File I/O¶
File I/O is non-blocking too.
(Something typically hard to do.)
Slide 51: File Stat Example¶
As an example, a program that outputs the last time /etc/passwd was modified:
var stat = require("posix").stat,
puts = require("sys").puts;
var promise = stat("/etc/passwd");
promise.addCallback(function (s) {
puts("modified: " + s.mtime);
});
Slide 52: Promises¶
A promise is a kind of EventEmitter which emits either "success" or "error". (But not both.)
All file operations return a promise.
Slide 53: Promise Syntax Sugar¶
promise.addCallback(cb)
is just API sugar for:
promise.addListener("success", cb)
Slide 54: Simple HTTP Server¶
var http = require("http");
http.createServer(function (req,res) {
res.sendHeader(200,
{"Content-Type": "text/plain"});
res.sendBody("Hello\r\n");
res.sendBody("World\r\n");
res.finish();
}).listen(8000);
Slide 55: HTTP Server Output¶
% node http_server.js &
[4] 27355
% curl -i http://localhost:8000/
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: keep-alive
Transfer-Encoding: chunked
Hello
World
%
Slide 56: Streaming HTTP Server¶
var http = require("http");
http.createServer(function (req,res) {
res.sendHeader(200,
{"Content-Type": "text/plain"});
res.sendBody("Hel");
res.sendBody("lo\r\n");
setTimeout(function () {
res.sendBody("World\r\n");
res.finish();
}, 2000);
}).listen(8000);
Slide 57: Streaming HTTP Output¶
% node http_server2.js &
[4] 27355
% curl http://localhost:8000/
Hello
# Two seconds later...
% node http_server2.js &
[4] 27355
% curl http://localhost:8000/
Hello
World
%
Slide 58: Executing Programs¶
var sys = require("sys");
sys.exec("ls -l /")
.addCallback(function (output) {
sys.puts(output);
});
Programs can be run with sys.exec()
Slide 59: Streaming Child Processes¶
But Node never forces buffering
∃ a lower-level facility to stream data through the STDIO of the child processes.
Simple IPC.
Slide 60: Child Process Example¶
var puts = require("sys").puts;
var cat =
process.createChildProcess("cat");
cat.addListener("output",
function (data) {
if (data) sys.puts(data);
});
cat.write("hello ");
cat.write("world\n");
cat.close();
Slide 61: Demo / Experiment¶
An IRC Daemon written in javascript.
irc.nodejs.org
node.js¶
Source code: - http://tinyurl.com/ircd-js - http://gist.github.com/a3d0bbbff196af633995
Slide 62: Internal Design¶
Slide 63: Dependencies¶
- V8 (Google)
- libev event loop library (Marc Lehmann)
- libeio thread pool library (Marc Lehmann)
- http-parser a ragel HTTP parser (Me)
- evcom stream socket library on top of libev (Me)
- udns non-blocking DNS resolver (Michael Tokarev)
Slide 64: Thread Pool Usage¶
Blocking (or possibly blocking) system calls are executed in the thread pool.
Signal handlers and thread pool callbacks are marshaled back into the main thread via a pipe.
Slide 65: File Descriptor Limitations¶
% node myscript.js < hugefile.txt
STDIN_FILENO will refer to a file.
Cannot select() on files;
read() will block.
Slide 66: Pumping Thread Solution¶
Solution: Start a pipe, and a “pumping thread”.
Pump data from blocking fd into pipe.
Main thread can poll for data on the pipe.
(See deps/coupling if you’re interested)
Slide 67: Future Plans¶
- Fix API warts.
- More modularity; break Node into shared objects.
- Include libraries for common databases in distribution.
- Improve performance.
- TLS support
- Web Worker-like API. (Probably using ChildProcess)
Slide 68: Version 0.2 Timeline¶
Future
Version 0.2 in late December or January.
Core API will be frozen.
Slide 69: Questions¶
Questions…?
http://nodejs.org/
ry@tinyclouds.org