{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Node.js pragmatics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Command-line arguments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Command-line arguments are contained in the `argv` property of the global `process` object. The `argv` property is an array with the arguments, represented as strings, beginning at index 2:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "['node', '/path/to/your/program.js', 'arg1', 'arg2', 'arg3'...]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Iterating through `process.argv`:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "6\n" ] }, { "data": { "text/plain": [ "undefined" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Simulate running a script file from the command line \n", "// with three numeric arguments\n", "process.argv = ['node', 'app.js', '1', '2', '3'];\n", "\n", "// Contents of imagined script file app.js\n", "var sum = 0;\n", "for (var i = 2, l = process.argv.length; i < l; i ++) {\n", "\n", " // process.argv elements are strings, so we coerce to numbers here\n", " sum += Number(process.argv[i]);\n", "}\n", "console.log(sum); // => 6" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "On the first line above, we set `process.argv` to an array that simulates running a script file from the command line with three numeric arguments, as if we wrote this at a bash prompt:\n", "\n", "`$ node app.js 1 2 3`\n", "\n", "The code that follows the first line above would reside in that script file `app.js`." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## File system in/out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For file system input, require the `fs` module and call its `readFile()` methods." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Synchronous (blocking) method" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var fs = require('fs');\n", "var myBufferObject = fs.readFileSync('./myFile.txt'); // filepath" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Stringifying the `Buffer` object returned by the `readFile()` methods of the `fs` module:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [], "source": [ "/* Read a file from a path specified as first command line argument\n", " and log number of lines in the file to the console */\n", "\n", "// Simulate command-line argument\n", "process.argv = ['node', 'app.js', './fileSystemInOut.txt'];\n", "\n", "// Require 'fs' (filesystem) module\n", "var fs = require('fs');\n", "\n", "/* Use synchronous (blocking) method. Returns a `Buffer` object.\n", " Remember that first CLI arg is `process.argv` index 2, not 0 */\n", "var myBufferObject = fs.readFileSync(process.argv[2]);\n", "\n", "/* Stringify the `Buffer` object and call `.split('\\n')` to create an\n", " array of elements separated by newlines */\n", "var myBufferObjectStringified = myBufferObject.toString();\n", "var myBufferObjectStringifiedArray = \n", " myBufferObjectStringified.split('\\n');\n", "\n", "/* Use length of the array created by `.split()`\n", " => \"./fileSystemInOut.txt contains 5 lines.\" */\n", "console.log(process.argv[2] + ' contains ' + \n", " myBufferObjectStringifiedArray.length + ' lines.');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More tersely:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var fs = require('fs')\n", "\n", "var contents = fs.readFileSync(process.argv[2])\n", "var lines = contents.toString().split('\\n').length" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also, the `fs` module's `readFile()` methods take an optional `encoding` parameter which will stringify the `Buffer` object, eliminating the need to call `.toString()`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var lines = fs.readFileSync(process.argv[2], 'utf8').split('\\n').length;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Asynchronous (non-blocking) method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Requires a callback. Here, we also check `error`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var fs = require('fs');\n", "\n", "var myBufferObject = fs.readFile('./myFile.txt', 'utf-8',\n", " function(error, contents) {\n", " if (error) throw error;\n", " console.log(contents);\n", " }\n", " );" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reading directory contents" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Filter list of files in directory by extension" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "// Simulate command-line argument\n", "process.argv = ['node', './app.js', './', 'js'];\n", "\n", "var fs = require('fs');\n", "\n", "// `Path` module provides `extname()` method we will use\n", "var path = require('path');\n", "\n", "// Call the `fs` module's `readdir()` method\n", "fs.readdir(process.argv[2], function(error, list) {\n", " if (error) throw error;\n", "\n", " for (var i = 0, l = list.length; i < l; i++) {\n", "\n", " // `path.extname()` returns file extension including '.'\n", " if (path.extname(list[i]) === '.' + process.argv[3]) {\n", " console.log(list[i]);\n", " }\n", " }\n", "});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This could also be accomplished using the `forEach()` method:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var fs = require('fs')\n", "var path = require('path')\n", "\n", "fs.readdir(process.argv[2], function (err, list) {\n", " list.forEach(function (file) {\n", " if (path.extname(file) === '.' + process.argv[3])\n", " console.log(file)\n", " })\n", "})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## HTTP" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basic HTTP call. (Use libraries `bl` or `concat-stream` instead for entire streams of data.)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "undefined" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Response: 200\n", "Something.\n", "Something.\n", "\n", "\n" ] } ], "source": [ "var http = require('http');\n", "\n", "function httpGet(url) {\n", " http.get(url, function (response) {\n", " console.log(\"Response: \" + response.statusCode);\n", " // Get string data rather than Node buffer object\n", " response.setEncoding('utf8');\n", " response.on('error', function(err) {\n", " console.err('Error: ' + err.message);\n", " });\n", " response.on('data', console.log);\n", " });\n", "}\n", "\n", "httpGet('http://www.something.com'); // => If 200, html from this url" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a basic HTTP server, require the `http` module and call its `createServer()` method, passing it a callback:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var http = require('http');\n", "\n", "http.createServer(function(request, response) {\n", " response.writeHead(200);\n", " response.end();\n", "}).listen(8080);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Serving the contents of a file from the filesystem:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var http = require('http');\n", "var fs = require('fs');\n", "\n", "http.createServer(function(request, response) {\n", " response.writeHead(200);\n", " fs.readFile('index.html', function(error, contents) {\n", " response.write(contents);\n", " response.end(); // End response here\n", " });\n", "}).listen(8080);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If this code is in a file named `server.js`, run it from the command line with `node server.js`, then use `curl http://localhost:8080` to see the server response." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Writing HTTP response headers along with a status code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "response.writeHead(200, {\n", " 'Content-Type': 'text/html',\n", " ...\n", "});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`response.end()` can take a parameter the value of which will be appended to the response:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var http = require('http');\n", "var fs = require('fs');\n", "\n", "http.createServer(function(request, response) {\n", " response.writeHead(200);\n", " fs.readFile('index.html', function(error, contents) {\n", " response.write(contents);\n", " response.end(\"Goodbye\");\n", " });\n", "}).listen(8080);" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "$ echo \"foo\" > index.html\n", "$ node server.js\n", "$ curl http://localhost:8080\n", "foo\n", "Goodbye" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exporting a single function from a module (the callback should be placed inside the appropriate block, and one should perform an error check somewhere using `if (error) return callback(error);`):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "module.exports = function(param1, param2, callback) {\n", " ...\n", " callback(null, fileArray);\n", "};" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using the module with the callback:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var myModule = require('myModule.js'); // <- looks in node_modules directory;\n", " // or you can use Unix pathnames\n", "\n", "myModule(param1, param1, function(error, data) {\n", " if (error) return console.error('Error: ' + error);\n", " ...\n", "});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exporting multiple functions from a module:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "exports.function1 = function() {};\n", "exports.function2 = function() {};" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var myModule = require('myModule.js');\n", "myModule.function1();\n", "myModule.function2();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Streams (stream API still has status Unstable in node v0.12.6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create read file stream and log chunks to console:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var fs = require('fs');\n", "\n", "var file = fs.createReadStream('myFile.txt');\n", "file.on('readable', function() {\n", " var chunk;\n", " while (null !== (chunk = file.read())) {\n", " console.log(chunk.toString());\n", " }\n", "});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pipe()` method instead:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "var fs = require('fs');\n", "\n", "var file = fs.createReadStream('myFile.txt');\n", "\n", "file.pipe(process.stdout);" ] } ], "metadata": { "kernelspec": { "display_name": "Javascript (Node.js)", "language": "javascript", "name": "javascript" }, "language_info": { "file_extension": "js", "mimetype": "application/javascript", "name": "javascript", "version": "0.12.6" } }, "nbformat": 4, "nbformat_minor": 0 }