Dev Watch

Blog archive

Classes, Modules and Promises: JavaScript Marches On

This JavaScript thing might just catch on.

The world's most popular programming language is starting to look like a real programming language, with classes, modules, promises and more. There's even a lot of excited discussion about proper tail calls and tail call optimization, whatever those are.

Imagine what a DHTML jockey frozen in 1999 would think of the language's amazing transformation if she reawakened now to see code like this:

var items = [...];
items.reduce(function(promise, item) {
  return promise.then(function(results) {
    return someFunctionAsync(item)
      .then(results.push.bind(results))
      .then(function() { return results; });
  });
}, Promise.resolve([]));

In my bumbling attempts to code JavaScript, I've been seeing more stuff like that, and this

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

and

var o = {p1:'foo', p2:'bar', p3: 'baz'};

I'm having a hard enough time figuring out regular JavaScript and have been just trying to ignore these mysterious things. In working through a pet instructional project based on a tutorial, I recently had to figure out how to download data using fetch instead of XMLHttpRequest, and use const and let instead of var. But now it looks like I'd better just accept change and try to wrap my mind around as much of this new stuff as I can.

Why now?

"Today we’ve reached an important milestone: V8 supports ES6 and ES7," reads a recent blog post from the team behind V8, the JavaScript engine powering the Chrome browser. "You can use the new language features today in Chrome Canary, and they will ship by default in the M52 release of Chromium."

Then I saw this a couple weeks ago:

WebKit is now 100 Percent Complete
[Click on image for larger view.] WebKit is now 100 Percent Complete (source: Twitter)

Yes, the open source browser engine that powers the Safari browser is the first major JavaScript engine to tick off all features of ECMAScript 2015 (or ES6, or ECMAScript 6, or ES2015, or ECMA-262, Edition 5 -- the naming conventions for JavaScript standards are almost as convoluted as the new JavaScript frameworks popping up every week -- talk about "JavaScript fatigue"). That's according to the ECMAScript compatibility table.

And just yesterday, Microsoft wrote about previewing ES6 modules and other new features in Chakra, the open source engine powering the Microsoft Edge browser. (Internet Explorer lags behind in these things, to the derision of Web developers everywhere.)

And Mozilla, the organization behind the Firefox browser, talks about ECMAScript Next support in Mozilla. But I'm not ready for TypedObjects objects or shared memory objects or additions to the ArrayBuffer object, thank you. Following is my rudimentary understanding of the new features coming in ES6 (and some in ES7) of most importance to a bumbling amateur hobbyist.

Classes
These are pretty easy to understand for just about every programmer exposed to object-oriented programming (OOP), which is just about every programmer nowadays. They're also pretty well supported by the latest editions of the major browsers, and Node.js and even (mostly) iOS 9, though not Android (the mobile engines seem to be running behind the browsers). Basically they pave the way for more OO in JavaScript.

"JavaScript classes are introduced in ECMAScript 6 and are syntactical sugar over JavaScript's existing prototype-based inheritance," says Mozilla (which provided the aforementioned Polygon class example snippet). "The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance."

A StrongLoop blog post echoes the "syntactic sugar" angle.

"ECMAScript 2015, formerly known as ECMAScript 6 (ES6), makes classes a first-class citizen by introducing a few new keywords," the post states. "At this time, however there are no new features when compared to the good old JavaScript prototypes. The new keywords are simply a syntax sugar on top of the well-established prototype system. This does make the code more readable and lays the path forward for new object oriented (OO) features in the upcoming spec releases.

"The reason for this is to ensure backwards compatibility with existing code written using the ES6 and ES5 spec. In other words, older code should be able to be run side by side without any workarounds or hacks."

Modules
Modules aid in composability, or the ability to break up large programs into smaller components that can be chained together and reused to obtain specific functionality. These chunks of code can be imported and exported into projects as needed.

In React Native, for example, you can create a viewK that simply displays an image in a certain way and store it in a file that ends with a module.exports = NewImage statement. You can then import (require) the file into your project and pass it the URI or location of the image you want to display.

According to the Exploring ES6 site, "JavaScript has had modules for a long time. However, they were implemented via libraries, not built into the language. ES6 is the first time that JavaScript has built-in modules. ES6 modules are stored in files. There is exactly one module per file and one file per module."

As the site explains, the new module features specified by ES6 are kind of a unification effort to address two incompatible module approaches in ES5: CommonJS modules (popular in Node.js) and Asynchronous Module Definition (AMD), implemented by RequireJS.

StrongLoop's take on modules picks up on that theme.

"ECMAScript 2015 (formerly known as ES6) introduces a completely new feature and concept to the front-end JavaScript world that strangely has been around for a very long time -- modules. ES2015 formalizes what CommonJS (the basis for modules in Node.js) and AMD have tried to address in an attempt to take all the strengths and leave out the weaknesses: Compact syntax and asynchronous and configurable module loading."

Promises
These are associated with introducing a kind of concurrency or parallelism (or a combination of the two) into the single-threaded JavaScript language.

"JavaScript is single threaded, meaning that two bits of script cannot run at the same time, they have to run one after another," says an article on HTML5 Rocks. "In browsers, JavaScript shares a thread with a load of other stuff. What that stuff is differs from browser to browser, but typically JavaScript is in the same queue as painting, updating styles, and handling user actions (such as highlighting text and interacting with form controls). Activity in one of these things delays the others."

A Promise object, the Mozilla Developer Network explains, "is used for deferred and asynchronous computations. A Promise represents an operation that hasn't completed yet, but is expected in the future."

Promises are put to use in the aforementioned fetch API I was forced to use in my React Native fumblings. In the following code, a request is made to download some JSON data, and then promises are indicated with the then function to do stuff with the data, like assign it to a variable:

fetch('https://api.github.com/users/' + name + '/events/public')
  .then((response) => response.json())
  .then((responseData) => {
    this.setState({
     jsonData: responseData
    });

Before promises, this functionality was handled with callbacks, functions called to do something with the returned data, like assign it to a variable after it's returned from an XMLHttpRequest call. But that approach can become cumbersome and problematic.

That's explained in a Twilio blog post titled Async/Await: The Hero JavaScript Deserved.

"Writing asynchronous code is hard," it says. "When it comes to JavaScript we rely heavily on callback functions to accomplish asynchronous tasks which can be unintuitive. This cognitive overhead creates a barrier to entry for newcomers to programming and the language and even causes frequent heartburn for those of us who have been using the language a while."

As noted in the blog title, promises are associated with Asynchronous Functions (async/await), which is actually a proposal for ECMAScript 2016 (or ES7, or ...).

With Asynchronous Functions, you can await on a promise, stopping (non-blocking) a function to wait for a promise to be resolved and return a value.

"The entire foundation for async/await is promises," says a Medium blog post by Daniel Brain. "In fact every async function you write will return a promise, and every single thing you await will ordinarily be a promise."

These things aren't welcomed by everybody, though as one developer commented in a recent Hacker News post: "Promises are like cancer, and async/await is just treating the symptoms." Check out the developer's further commentary to see why.

Promises and async/await functionality was already available by using the Babel transpiler, but it's getting formalized and baked into JavaScript.

Other things are getting baked in, too, like arrow functions, destructuring assignments (both featured in the previously listed code snippets) and much, much more. You can read about them here, because I'm getting my own kind of JavaScript fatigue writing about them (or ECMAScript fatigue, or ES fatigue, or ...).

What's your favorite new JavaScript feature? Share your thoughts here or drop me a line.

Posted by David Ramel on May 18, 2016