Table of Contents for
Node.js 8 the Right Way

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Node.js 8 the Right Way by Jim Wilson Published by Pragmatic Bookshelf, 2018
  1. Title Page
  2. Node.js 8 the Right Way
  3. Node.js 8 the Right Way
  4. Node.js 8 the Right Way
  5. Node.js 8 the Right Way
  6.  Acknowledgments
  7.  Preface
  8. Why Node.js the Right Way?
  9. What’s in This Book
  10. What This Book Is Not
  11. Code Examples and Conventions
  12. Online Resources
  13. Part I. Getting Up to Speed on Node.js 8
  14. 1. Getting Started
  15. Thinking Beyond the web
  16. Node.js’s Niche
  17. How Node.js Applications Work
  18. Aspects of Node.js Development
  19. Installing Node.js
  20. 2. Wrangling the File System
  21. Programming for the Node.js Event Loop
  22. Spawning a Child Process
  23. Capturing Data from an EventEmitter
  24. Reading and Writing Files Asynchronously
  25. The Two Phases of a Node.js Program
  26. Wrapping Up
  27. 3. Networking with Sockets
  28. Listening for Socket Connections
  29. Implementing a Messaging Protocol
  30. Creating Socket Client Connections
  31. Testing Network Application Functionality
  32. Extending Core Classes in Custom Modules
  33. Developing Unit Tests with Mocha
  34. Wrapping Up
  35. 4. Connecting Robust Microservices
  36. Installing ØMQ
  37. Publishing and Subscribing to Messages
  38. Responding to Requests
  39. Routing and Dealing Messages
  40. Clustering Node.js Processes
  41. Pushing and Pulling Messages
  42. Wrapping Up
  43. Node.js 8 the Right Way
  44. Part II. Working with Data
  45. 5. Transforming Data and Testing Continuously
  46. Procuring External Data
  47. Behavior-Driven Development with Mocha and Chai
  48. Extracting Data from XML with Cheerio
  49. Processing Data Files Sequentially
  50. Debugging Tests with Chrome DevTools
  51. Wrapping Up
  52. 6. Commanding Databases
  53. Introducing Elasticsearch
  54. Creating a Command-Line Program in Node.js with Commander
  55. Using request to Fetch JSON over HTTP
  56. Shaping JSON with jq
  57. Inserting Elasticsearch Documents in Bulk
  58. Implementing an Elasticsearch Query Command
  59. Wrapping Up
  60. Node.js 8 the Right Way
  61. Part III. Creating an Application from the Ground Up
  62. 7. Developing RESTful Web Services
  63. Advantages of Express
  64. Serving APIs with Express
  65. Writing Modular Express Services
  66. Keeping Services Running with nodemon
  67. Adding Search APIs
  68. Simplifying Code Flows with Promises
  69. Manipulating Documents RESTfully
  70. Emulating Synchronous Style with async and await
  71. Providing an Async Handler Function to Express
  72. Wrapping Up
  73. 8. Creating a Beautiful User Experience
  74. Getting Started with webpack
  75. Generating Your First webpack Bundle
  76. Sprucing Up Your UI with Bootstrap
  77. Bringing in Bootstrap JavaScript and jQuery
  78. Transpiling with TypeScript
  79. Templating HTML with Handlebars
  80. Implementing hashChange Navigation
  81. Listing Objects in a View
  82. Saving Data with a Form
  83. Wrapping Up
  84. 9. Fortifying Your Application
  85. Setting Up the Initial Project
  86. Managing User Sessions in Express
  87. Adding Authentication UI Elements
  88. Setting Up Passport
  89. Authenticating with Facebook, Twitter, and Google
  90. Composing an Express Router
  91. Bringing in the Book Bundle UI
  92. Serving in Production
  93. Wrapping Up
  94. Node.js 8 the Right Way
  95. 10. BONUS: Developing Flows with Node-RED
  96. Setting Up Node-RED
  97. Securing Node-RED
  98. Developing a Node-RED Flow
  99. Creating HTTP APIs with Node-RED
  100. Handling Errors in Node-RED Flows
  101. Wrapping Up
  102. A1. Setting Up Angular
  103. A2. Setting Up React
  104. Node.js 8 the Right Way

Programming for the Node.js Event Loop

Let’s get started by developing a couple of simple programs that watch files for changes and read arguments from the command line. Even though they’re short, these applications offer insights into Node.js’s event-based architecture.

Watching a File for Changes

Watching files for changes is a convenient problem to start with because it demands asynchronous coding while demonstrating important Node.js concepts. Taking action whenever a file changes is just plain useful in a number of cases, ranging from automated deployments to running unit tests.

Open a terminal to begin. Create a new directory called filesystem and navigate down into it.

 $ ​​mkdir​​ ​​filesystem
 $ ​​cd​​ ​​filesystem

You’ll use this directory for all of the code examples in this chapter. Once there, use the touch command to create a file called target.txt.

 $ ​​touch​​ ​​target.txt

If you’re in an environment that doesn’t have the touch command (like Windows), you can alternatively echo something to write the file.

 $ ​​echo,​​ ​​>​​ ​​target.txt

This file will be the target for our watcher program. Now open your favorite text editor and enter the following:

 'use strict'​;
 const​ fs = require(​'fs'​);
 fs.watch(​'target.txt'​, () => console.log(​'File changed!'​));
 console.log(​'Now watching target.txt for changes...'​);

Save this file as watcher.js in the filesystem directory alongside the target.txt file. Although this is a short program, it deserves scrutiny since it takes advantage of a number of JavaScript and Node.js features. Let’s step through it.

The program begins with the string ’use strict’ at the top. This causes the program to be executed in strict mode, a feature introduced in ECMAScript version 5. Strict mode disables certain problematic JavaScript language features and makes others throw exceptions. It’s always a good idea to use strict mode, and we’ll use it throughout the book.

Next, notice the const keyword; this sets up fs to be a local variable with a constant value. A variable declared with const must be assigned a value when declared, and can never have anything assigned to it again (which would cause a runtime error).

It might surprise you, but it turns out that most of the time, in most code, variables don’t need to be reassigned, making const a good default choice for declaring variables. The alternative to const is let, which we’ll discuss shortly.

The require() function pulls in a Node.js module and returns it. In our case, we’re calling require(’fs’) to incorporate Node.js’s built-in filesystem module.[17]

In Node.js, a module is a self-contained bit of JavaScript that provides functionality to be used elsewhere. The output of require() is usually a plain old JavaScript object, but may also be a function. Modules can depend on other modules, much like libraries in other programming environments, which import or #include other libraries.

Next we call the fs module’s watch() method, which takes a path to a file and a callback function to invoke whenever the file changes. In JavaScript, functions are first-class citizens. This means they can be assigned to variables and passed as parameters to other functions. Take a close look at our callback function:

 () => console.log(​'File changed!'​)

This is an arrow-function expression, sometimes called a fat arrow function or just an arrow function. The empty pair of parentheses () at the beginning means this function expects no arguments. Then the body of the function uses console.log to echo a message to standard output.

Arrow functions are new in ECMAScript 2015 and you’ll be writing many such functions throughout this book. Prior to the introduction of arrow functions, you’d have supplied a callback using the more verbose function(){} construction:

 function​() {
  console.log(​'File changed!'​);
 }

Aside from having a terser syntax than older function expressions, arrow functions have another big advantage over their ancestral counterparts: they do not create a new scope for this. Dealing with this has been a thorn in the side of many JavaScript developers over the years, but thanks to arrow functions, it’s no longer a major source of consternation. Just like const should be your go-to means of declaring variables, arrow functions should be your first choice in declaring function expressions (such as callbacks).

The last line of the program just informs you that everything is ready. Let’s try it out! Return to the command line and launch the watcher program using node, like so:

 $ ​​node​​ ​​watcher.js
 Now watching target.txt for changes...

After the program starts, Node.js will patiently wait until the target file is changed. To trigger a change, open another terminal to the same directory and touch the file again. The terminal running watcher.js will output the string File changed!, and then the program will go back to waiting.

If you see duplicate messages, particularly on Mac OS X or Windows, this is not a bug in your code! There are a number of known issues around this, and many have to do with how the operating system surfaces changes.

Since you’ll be touching the target file a lot this chapter to trigger changes, you might want to use the watch command to do this automatically:

 $ ​​watch​​ ​​-n​​ ​​1​​ ​​touch​​ ​​target.txt

This command will touch the target file once every second until you stop it. If you’re on a system that doesn’t have the watch command, don’t worry. Any means of writing to target.txt is fine.

Visualizing the Event Loop

The program we wrote in the last section is a good example of the Node.js event loop at work. Recall the event-loop figure from How Node.js Applications Work. Our simple file-watcher program causes Node.js to go through each of these steps, one by one.

To run the program, Node.js does the following:

  • It loads the script, running all the way through to the last line, which produces the Now watching message in the console.

  • It sees that there’s more to do because of the call to fs.watch.

  • It waits for something to happen—namely, for the fs module to observe a change to the file.

  • It executes our callback function when the change is detected.

  • It determines that the program still has not finished, and resumes waiting.

In Node.js the event loop spins until there’s nothing left to do, there’s nothing left to wait for, or the program exits by some other means. For example, if an exception is thrown and not caught, the process will exit. We’ll look at how this works next.

Reading Command-Line Arguments

Now let’s make our program more useful by taking in the file to watch as a command-line argument. This will introduce the process global object and how Node.js deals with exceptions.

Open your editor and enter this:

 const​ fs = require(​'fs'​);
 const​ filename = process.argv[2];
 if​ (!filename) {
 throw​ Error(​'A file to watch must be specified!'​);
 }
 fs.watch(filename, () => console.log(​`File ​${filename}​ changed!`​));
 console.log(​`Now watching ​${filename}​ for changes...`​);

Save the file as watcher-argv.js and run it like so:

 $ ​​node​​ ​​watcher-argv.js​​ ​​target.txt
 Now watching target.txt for changes...

You should see output and behavior that’s nearly identical to that of the first watcher.js program. After outputting Now watching target.txt for changes... the script will diligently wait for changes to the target file.

This program uses process.argv to access the incoming command-line arguments. argv stands for argument vector; it’s an array containing node and the full path to the watcher-argv.js as its first two elements. The third element (that is, at index 2) is target.txt, the name of our target file.

Note the use of backtick characters () to mark the strings logged in this program:

 `File ​${filename}​ changed!`

These are called template strings. They can span multiple lines and they support expression interpolation, meaning you can place an expression inside of ${} and it will insert the stringified result.

If a target filename is not provided to watcher-argv.js, the program will throw an exception. You see try that by simply omitting the target.txt parameter:

 $ ​​node​​ ​​watcher-argv.js
 /full/path/to/script/watcher-argv.js:4
  throw Error('A file to watch must be specified!');
  ^
 
 Error: A file to watch must be specified!

Any unhandled exception thrown in Node.js will halt the process. The exception output shows the offending file and the line number and position of the exception.

Processes are important in Node. It’s pretty common in Node.js development to spawn separate processes as a way of breaking up work, rather than putting everything into one big Node.js program. In the next section, you’ll learn how to spawn a process in Node.