Node.js - KeynesYouDigIt/Knowledge GitHub Wiki
Why server-side JS?
- Node is fast
- Non-blocking IO
- Uses Google's V8 engine
- One language to rule them all
- Good standard library
- npm
Why not server-side JS?
- You have to think in async
- Has maturity issues
- Callback hell
- JavaScript has quirks
Single-threaded
- Single-threaded has advantages over threaded
- Node has an event loop handling all requests, which it delegates to POSIX async threads
- Restaurant metaphor -> one waiter who just takes orders and delivers food vs. 10 waiters who do everything
- Don’t use node for CPU intensive tasks (video processing).
Node Core
- V8 (the engine)
- Libev: The event loop
- LibEio: Async I/O
- LibUv: Abstraction on libEio, libev, etc
- A standard library
_[this stuff in action] - Case Study::why batching requests is faster than making many individual requests.
Global Node objects:
process
- Running processrequire
- Function to require packageconsole
console
object is similar, but differentconsole.error
prints tostderr
console.trace()
to show stack trace
global
http
- Has to be imported- No
document
,window
,DOM
Modules:
var express = require("express");
- Can be a JS file or a JSON file
- If the thing isn't a file, it looks inside for an
index.js
file. - Don't have side effects in your modules.
- 4 ways to require:
require("fs")
- Core module or fromnode_modules
folderrequire("./something")
- For arbitrary filesrequire("../config.json")
- For arbitrary filesrequire
returns whatever is hanging off ofmodule.exports
in that file
- You can immediately invoke modules
- You can export anything (function, object, whatever)
Module Patterns
- Simple Object API
- Hide private variables
- Returning an object literal
- Revealing Module
var MyModule = (function(){
function hiddenMethod() {
return "hey";
}
return {
publicMethod: privateMethod
};
})();
MyModule.privateMethod(); // undefined
MyModule.publicMethod(); // "hey"
- Modules are cached- it's the same object!! Returning just an object is a singleton.
- Object constructor (returns an object with a prototype chain)
npm
- Is the tool,
npm
- Has publishing tools (can include tasks)
- Is the site, https://www.npm.org
- Is the registry (which is not the actual packages, just pointers to them)
- Can be public or private
- Project Metadata is in
package.json
- Create one with
npm init
- Create one with
- Setting up
npm
defaults:npm set init.author.name "Kyle Coberly"
npm set init.author.email "[email protected]"
npm set init.author.url "www.kylecoberly.com"
- Installing locally
npm install package_name
to trynpm install --save package_name
to install production dependencynpm install --save-dev package_name
to install development dependency
- Installing globally
npm install -g package_name
npm ls
,npm -g
to list installed packages
Semantic versioning
~1
,~1.1
goes for highest minor or patch versionnpm shrinkwrap
- Snapshots every versionnpm search
- Looks for packages, kind of sucks, use Googlenpm update
- Updates registrynpm rm --save
- Deletes a package
Process
- The process object has the environment variables, can kill processes, access the shell, etc.
process.env; // {
SHELL: "/bin/zsh",
USER: "kylecoberly",
HOME: "/home/kylecoberly",
PORT: 3000,
NODE_ENV: "development"
}
- Get arguments via
process.argv
- Takes the command line as space-delimited tokens
- Doesn't parse anything
- Includes
node
- Returns array
- To kill node:
process.exit(0)
for successprocess.exit(127)
for failure
- To respond to signals:
process.on("eventName", function(error){
console.log("error", error);
});
- POSIX codes from OS:
SIGINT
,ENONT
,EADDRINUSE
http
/https
module
- Write and handle HTTP/HTTPS requests
- Use package to auto load on change = nodemon, eg- nodemon server.js
var http = require("http");
var server = http.createServer(function handleRequests(request, response){
response.writeHead(200, {
"Content-Type": "text/plain",
"X-My-Thing": "The internet"
});
response.end("Hello world!");
});
server.listen(3000, "127.0.0.1", function(){
console.log("It's up!");
})
child_process
Module
- Allows you to create sub-processes.
spawn
is an instance of theChildProcess
class. Close the input stream to allow the spawned process to continue running.
var execute = require("child_process").exec;
var ps = execute("ps aux", function (err, stdout, stderr){
// Do something
};
var spawn = require("child_process").spawn;
var someEvent = spawn("someEvent", ["something"]);
someEvent.stdout.on("data", function(data){
tee.stdin.write(data);
};
Standard streams
STDIN
,STDOUT
,STDERR
- Event emitters that have standard events. They are pluggable.
.data()
,.write()
,.end()
,.pipe()
- Whether it's readable/writeable can depend on perspective
STDOUT
andSTDERR
are both blocking. Special streams!stream.tty
will tell you if the user is using it directly, rather than a program
STDIN
- To listen in on data from stdin, use the
data
andend
events data
is input fed to the program. This may trigger multiple times.end
says the you’re done reading.STDIN
is paused by default
STDOUT
write()
to write toSTDOUT
STDERR
- For logging, usually
Buffers
- Buffers are chunks of binary data in memory
- For larger data sets or if you don’t how much of something you'll have:
buffer = new Buffer(26); buffer.toString("utf8", 0, 5);
Filesystem IO
- File handling can/should be non-blocking. That's what makes it "web scalable".
- Check that it exists before you start reading
- Don't respond with errors for files that users don't have permissions to access
fs
- File system is core module
- Race conditions = When something is no longer true after you check it
- Don’t use the sync version of the fs methods! Won’t scale!
fs.readFile("file/path", {options}, function(error, contents){
if (error){
// throw...
}
console.log(contents);
});
fs Methods
fs.writeFile();
fs.appendFile();
fs.exists();
fs.stats.isFile()
fs.stats.isDirectory()
fs.stats.isSocket()
fs.stats.size
fs.stats.mtime
fs.link(“src”, “dest”, “file” callback);
fs.unlink(); // delete
fs.mkdir();
fs.readdir();
fs.rmdir();
Sync vs. Async
process.nextTick();
- All async functions require callbacks.
- Callback hell - fight with event emitters, named functions, library, or promises
callback
andnext
mean the same thing
- Event emitter is a string with a corresponding callback
- Events are an imported module
- Can also inherit from util.
emitter.listeners(eventName)
emitter.on(eventName, listener)
emitter.once(eventName, listener)
emitter.removeListener(eventName, listener);
Connecting to Databases
- Install driver module
- Create a connection
- Connect it
- Query it
Connecting to Mongo
- Require MongoClient
- Declare URL
- Connect with mongo
- MongoLab = free cloud instances
Scaling
Vertical scaling (within server)
- Node is fast, but single-threaded. This means every request uses the same process.
- Non-blocking code ensures that something else is handling async requests, usually via callbacks.
- unclustered node app only using one core.
- Clustered node app can use every core.
cluster
module- Call cluster.fork() once per CPU core
- Strongloop Process Manager does this for you
Horizontal scaling (across servers)
- Scalability is gained by putting a load balancer in front of multiple servers.
Framework Patterns
- KISS Servers: small core, small modules (Node core)
- Convention: follow the leader, steep learning curve (Express, restify, Total.js)
- Configuration: open path, manual effort for advanced (Hapi, Kraken)
- ORM & Isomorphic: model-driven, shared code, steep learning (Loopback, Sails, Meteor)
Server-side Events
- One way, part of HTML5
EventSource
- Add event listeners in your code
- Two newlines is “end of message”
- Don’t close the connection
- Accept-Type: Event-Stream
Debugging
DEBUG
library- built-in debugger
- Node Inspector = Chome dev tools for node. Use Chrome debugger, etc.