Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Node.js Crash Course

DZone's Guide to

Node.js Crash Course

If you're new to Node.js, there is a lot to learn. This post gives a brief crash course in the language and its tools to help get you started!

· Web Dev Zone ·
Free Resource

Jumpstart your Angular applications with Indigo.Design, a unified platform for visual design, UX prototyping, code generation, and app development.

Introduction

I’ve been doing Node full-time at work and noticed a lot of other people lacking a centralized resource to get up and running quickly. There are a lot of wonderful resources out there for Node that are only a Google search away, but, hopefully, this document should get you coding quickly and help you to communicate effectively with other Node developers.

I’ve tried to write this list in order of the most important things you need to know. Feel free to skip around.

Node Version Manager (NVM)

Node changes often. To quickly change which version you’re using, install NVM. I’ve put nvm use stable in my .bash_profile so whenever I open a terminal, it uses the latest version. If this is confusing or doesn’t work, simply download the latest installable from nodejs.org.

Running and Testing Node

Open a command line and type node. To get out, on your keyboard press Control + C. While in the Node terminal, you can write JavaScript, and import modules to test them.

To run a JavaScript file, simply cd to the directory of the code, and in your command line, type node yourfile.js.

Modules

To share code, you use modules. There are 2 types of modules: CommonJS and ES6 (ignore AMD for now). CommonJS is what Node started with, and then browsers adopted ES6. Node 9 will officially adopt ES6 modules, but, for now, ignore that and focus on CommonJS modules since they work with Node, both old and new.

The easiest way is to define functions/variables, then at the very bottom, put them in a list.

Simple

// a function and a variable
const cow = () => 'cow';
const AGE = 38;
// every Node.js file gets this module.exports global object
// There are a variety of ways to use it, but the easiest
// is to define an object, and put your variables in functions in it
// at the bottom of the file
module.exports = {
    cow,
    AGE
};
// use it in index.js
const {
    cow,
    AGE
} = require('./cow');
console.log("cow:", cow());

Big One

When you have a higher module that imports a bunch of child ones, you can enforce the user to require subfolders like this:

const Maybe = require('./some/deep/folder/thing.js');

This is fine. But, another way to suggest what the user should use is to only expose that in a higher module:

// your library/index.js
const Maybe = require('./library/some/deep/folder/thing.js');
const CHICKEN = 'Sooo Goood, mannnn....';
const {
    cow,
    AGE
} = require('./cow');
// we don't expose AGE, but everything else is ok.
// we also organize things
module.exports = {
    functional: {
        Maybe
    },
    animals: {
        CHICKEN,
        cow
    }
};
// use it in index.js
const yourLib = require('./library');
const result = yourLib.animals.cow();
console.log("result:", result); // cow

What Are These Weird, Empty Functions at the Top of My File?

If you see things like:

(function() {
...
})();

Where the majority of the code is in the . . . part, that’s called an Immediately Invoked Function Expression. It’s an old pattern used in the client-side/browser and is not needed or used in Node. Simple remove the top/bottom parts and manually expose the functions/variables you wish to use.

Modify Dependency Injection

If you see this version:

(function(window, undefined) {

That’s the browser's way of performing dependency injection, specifically to help remove global variables. While things like window and document are globals, global variables make things hard to test, so this allows you to pass those values in during testing and runtime. Refactor the functions that use those globals as function parameters.

Functions vs. Arrow Functions

There are a variety of ways to define functions in JavaScript. The 2 most common ways in Node are old sch00l function declarations and arrow functions.

Old Functions

The old way of defining functions is:

function nameOfIt() {
    ...
}

The powers that these named function declarations have are:

  1. You can forward reference them, meaning you can call them from higher up in the code before they’re actually defined in the file if you write imperative code.
  2. They have a built-in arguments property that is an array of the arguments passed into the function.
  3. They have a this keyword which allows various forms of Object Orientated Programming.
  4. Older browsers provide more informative stack traces because the function name is included in the stack trace vs. an anonymous function (Node doesn’t have this problem).

Arrow Functions

None of those things are needed anymore, especially in Node where stateful OOP doesn’t really exist in stateless server applications. That said, many developers still use classes.

Arrow functions have the following differences:

  1. No this, instead they adopt whatever scope they are in. If you never use this or scope, then you have none of those problems.
  2. No arguments property. If you wish to use something like that, you can define a function by using rest parameters, like addNumbers(...numbers). This makes the numbers property an Array of arguments; otherwise, you'll have an empty Array.
  3. They are treated like anonymous JavaScript functions, which means they are normal variables and you cannot forward reference them. That problem only occurs if you write imperative code. Calling an one arrow function from another arrow function works fine.
  4. They automatically return values unless you add {} to the function block. This removal of the need to manually write return combined with the removal of the need to write the word function leads to much smaller functions.

You should use Arrow Functions unless you know why you should be using older functions.

Arrow Functions With One Parameter

Typically, you write an Arrow function with a parameter like this:

const sayName = (name) => console.log("Hello " + name);

However, if you just have one argument, the () are optional:

const sayName = name => console.log("Hello " + name);

Arrow Function Line Length

While smaller, two new problems are created using lots of arrow functions. The first is, the line length can still get pretty long as you try to put everything on one line. Some ESLint rules written by jerks yell about this. The second is you’ll start having functions return functions, especially with Promises, and it gets unwieldy to read.

You cannot break them into multiple lines after the equal:

// wrong
const sayName =
    name => console.log("Hello " + name);

But you can line break after the fat arrow:

// correct
const sayName = name =>
    console.log("Hello " + name);

This helps with nested functions since we don’t have pipe operators like Elm or Elixir.

Common Pitfall

Debugging one-line arrow functions that are composed together can be a bit challenging. You have three options here.

const add = (a, b) => a + b;

The first is to break it out into a multi-line, imperative style function:

const add = (a, b) => {
    console.log("a:", a);
    console.log("b:", b);
    const result = a + b;
    console.log("result:", result);
    return result;
};

The challenge is to remember to use the return keyword to return the result once you go back to multiple line arrow functions.

The second option is to use an || (or) statement to log your information first. Since console is a noop ( a function that returns no value), it’ll return undefined, and trigger the code to the right of the || operator.

const add = (a, b) => console.log("a:", a) || a + b;

The third option is to use a modern IDE like Visual Studio Code that supports adding breakpoints on columns.

Truthy/Falsey

if (thing)

JavaScript has lax operators for Boolean evaluation. In short, they suck, hence we call them “truthy” and “falsey.” They aren’t very exact.

You have a few options:

  1. Learn them and look smart, yet have to continually remind your coworkers.
  2. Ignore them and don’t go down that path and use Lodash.

For example, this prints out “it’s true, homey”:

const cow = true;
if (cow) {
    console.log("it's true, homey");
}

So does this:

const cow = 'false';
if (cow) {
    console.log("it's true, homey");
}

The same holds true for nothing using equality vs strict equality in JavaScript:

null == undefined; // true
null === undefined; // false

Ignore it and all the weird edge cases. Create predicate functions using Lodash, and your problems go away, and your code works in all browsers and in Node versions.

Nots

You’ll occasionally see people do if(!thing) {. It basically means !==true.

Equality

Comparison operators in JavaScript are broken. You can learn the differences if you care to, but they are too hard to remember and don’t really help you write better code. Don’t use two equals, use three:

// wrong
if(thing == false)
// correct
if(thing === false)

Asynchronous Programming

JavaScript, unlike other programming languages, is asynchronous by default. Learn more to understand how to avoid creating race conditions as well as helpful tips if you come from C#. If you’re from Scala, JavaScript’s Promises are like Scala’s Futures.

In short, JavaScript does not stop or “block” on a line of code while an asynchronous operation such as an HTTP request, file read, or database call is run. Instead, you can give it a function to call later when it’s done, and your code keeps running in the current call stack. I’ve written an article that hopefully gives you clear examples of asynchronous programming.

Callbacks vs. Promises

The old way to code in Node is using callbacks. The new way is Promises. Since it is an opinion, Node continues to support callback APIs and create new APIs using callbacks. While callbacks can result in callback hell, so can Promises.

Either way, callbacks sadly are noops, meaning they don’t return a value. We don’t do that in functional programming, and neither should you. While newer versions of node support promisify, you should be using Promises because:

  1. They always return a value.
  2. They have built-in try/catch
  3. They are a native, finite state machine.
  4. They use Left/Right functional programming error handling fall through.

This leads to easier unit testing, more composable functions, and easier to debug code.

Best article to learn Promises is to learn how Promises are used wrong.

That said, if callbacks are easier for you, and you’re stuck with Promise based code, Node 9 has a way to convert them back to callbacks.

Command Line

To build command line Node apps, check out Commander.

Object-Oriented Programming

The basics of classes with inheritance work in the latest browser and Node without the need of a transpiler/compiler using ES6. However, transpilers offer a lot of nice features that, if you’re from an OOP background, it’s worth your time to check out.

For the basics, check out the Babel compiler. For a language, compiler, and simpler parallelism functionality, with runtime exceptions for non-prod code, check out Google’s Dart. For another great typed language with a helpful compiler, check out Microsoft’s TypeScript. Facebook has Flow in much the same vein.

Be aware, a lot of the marketing of the above tools target browser developers, but many work fine for Node. The beauty of Node is you “can just write code and run it” without waiting for a recompile, but for many, this isn’t a problem.

Functional Programming

You have two options: use libraries or a transpiler.

For libraries, Folktale v2 follows the Fantasy Land spec. Lodash has both functional methods as well as array comprehensions, and low-level JavaScript predicates.

If the mutable state and impurity of JavaScript is too much, you can use Facebooks’ OCAML influenced Reason, or Haskell influenced PureScript.

Unit and Integration Testing

To unit test, the four main test runners are Tape, Jasmine, Mocha, and Jest. I like Mocha. Mocha has an assertion library, Chai. For code coverage, use Istanbul. To prevent unit tests from accidentally becoming integration tests that make HTTP calls and other HTTP exceptions, use Nock. For mocking and spies (you poor thing) use Sinon. For integration testing, check out Supertest.

Take a look at the Indigo.Design sample applications to learn more about how apps are created with design to code software.

Topics:
functions ,node.js ,javascript ,web dev

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}