Book Image

Node.js Web Development - Fourth Edition

By : David Herron
Book Image

Node.js Web Development - Fourth Edition

By: David Herron

Overview of this book

Node.js is a server-side JavaScript platform using an event-driven, non-blocking I/O model allowing users to build fast and scalable data-intensive applications running in real time. This book gives you an excellent starting point, bringing you straight to the heart of developing web applications with Node.js. You will progress from a rudimentary knowledge of JavaScript and server-side development to being able to create, maintain, deploy and test your own Node.js application.You will understand the importance of transitioning to functions that return Promise objects, and the difference between fs, fs/promises and fs-extra. With this book you'll learn how to use the HTTP Server and Client objects, data storage with both SQL and MongoDB databases, real-time applications with Socket.IO, mobile-first theming with Bootstrap, microservice deployment with Docker, authenticating against third-party services using OAuth, and use some well known tools to beef up security of Express 4.16 applications.
Table of Contents (14 chapters)

Embracing advances in the JavaScript language

The last couple of years have been an exciting time for JavaScript programmers. The TC-39 committee that oversees the ECMAScript standard has added many new features, some of which are syntactic sugar, but several of which have propelled us into a whole new era of JavaScript programming. By itself, the async/await feature promises us a way out of what's called Callback Hell, or the situation we find ourselves in when nesting callbacks within callbacks. It's such an important feature that it should necessitate a broad rethinking of the prevailing callback-oriented paradigm in Node.js and the rest of the JavaScript ecosystem.

Refer back a few pages to this:

query('SELECT * from db', function (err, result) { 
    if (err) throw err; // handle errors 
    // operate on result 
});

This was an important insight on Ryan Dahl's part, and is what propelled Node.js's popularity. Certain actions take a long time to run, such as database queries, and should not be treated the same as operations that quickly retrieve data from memory. Because of the nature of the JavaScript language, Node.js had to express this asynchronous coding construct in an unnatural way. The results do not appear at the next line of code, but instead appear within this callback function. Further, errors have to be handled in an unnatural way, inside that callback function. 

The convention in Node.js is that the first parameter to a callback function is an error indicator, and the subsequent parameters are the results. This is a useful convention that you'll find all across the Node.js landscape. However, it complicates working with results and errors because both land in an inconvenient location — that callback function. The natural place for errors and results to land is on the subsequent line(s) of code.

We descend further into callback hell with each layer of callback function nesting. The seventh layer of callback nesting is more complex than the sixth layer of callback nesting. Why? If nothing else, it's that the special considerations for error handling become ever more complex as callbacks are nested more deeply.

var results = await query('SELECT * from db');

Instead, ES2017 async functions return us to this very natural expression of programming intent. Results and errors land in the correct location, while preserving the excellent event-driven asynchronous programming model that made Node.js great. We'll see later in the book how this works.

The TC-39 committee added many more new features to JavaScript, such as:

  • An improved syntax for Class declarations making object inheritance and getter/setter functions very natural.
  • A new module format that is standardized across browsers and Node.js.
  • New methods for strings, such as the template string notation.
  • New methods for collections and arrays — for example, operations for map/reduce/filter.
  • The const keyword to define variables that cannot be changed, and the let keyword to define variables whose scope is limited to the block in which they're declared, rather than hoisted to the front of the function.
  • New looping constructs, and an iteration protocol that works with those new loops.
  • A new kind of function, the arrow function, which is lighter weight meaning less memory and execution time impact
  • The Promise object represents a result that is promised to be delivered in the future. By themselves, Promises can mitigate the callback hell problem, and they form part of the basis for async functions.
  • Generator functions are an intriguing way to represent asynchronous iteration over a set of values. More importantly, they form the other half of the basis for async functions.

You may see the new JavaScript described as ES6 or ES2017. What's the preferred name to describe the version of JavaScript that is being used?

ES1 through ES5 marked various phases of JavaScript's development. ES5 was released in 2009, and is widely implemented in modern browsers. Starting with ES6, the TC-39 committee decided to change the naming convention because of their intention to add new language features every year. Therefore, the language version name now includes the year, hence ES2015 was released in 2015, ES2016 was released in 2016, and ES2017 was released in 2017.

Deploying ES2015/2016/2017/2018 JavaScript code

The pink elephant in the room is that, because of how JavaScript is delivered to the world, we cannot just start using the latest ES2017 features. In frontend JavaScript, we are limited by the fact that old browsers are still in use. Internet Explorer version 6 has fortunately been almost completely retired, but there are still plenty of old browsers installed on older computers that are still serving a valid role for their owners. Old browsers mean old JavaScript implementations, and if we want our code to work, we need it to be compatible with old browsers.

Using code rewriting tools such as Babel, some of the new features can be retrofitted to function on some of the older browsers. Frontend JavaScript programmers can adopt (some of) the new features at the cost of a more complex build toolchain, and the risk of bugs introduced by the code rewriting process. Some may wish to do that, while others will prefer to wait a while.

The Node.js world doesn't have this problem. Node.js has rapidly adopted ES2015/2016/2017 features as quickly as they were implemented in the V8 engine. With Node.js 8, we can now use async functions as a native feature, and most of the ES2015/2016 features became available with Node.js version 6. The new module format is now supported in Node.js version 10.

In other words, while frontend JavaScript programmers can argue that they must wait a couple of years before adopting ES2015/2016/2017 features, Node.js programmers have no need to wait. We can simply use the new features without needing any code rewriting tools.