Tag Archives: ES2016

Previewing ES6 Modules and more from ES2015, ES2016 and beyond

Chakra, the recently open-sourced JavaScript engine that powers Microsoft Edge and Universal Windows applications, has been pushing the leading edge of ECMAScript language support.  Most of ES2015 (aka ES6) language support is already available in Edge, and last week’s Windows Insider Preview build 14342 brings more ES6 capabilities including modules, default parameters, and destructuring. We’re not stopping there – Edge also supports all ES2016 (aka ES7) proposals – the exponentiation operator and Array.prototype.includes – as well as future ECMAScript proposals such as Async Functions and utility methods like Object.values/entries and String.prototype.padStart/padEnd.

ES6 Modules

Modules let you write componentized and sharable code. Without complete support from any browser, developers have already started to get a taste of ES6 modules through transpiling from tools such as TypeScript or Babel. Edge now has early support for ES6 modules behind an experimental flag.

Modules aren’t exactly new to JavaScript with formats such as Asynchronous Module Definition (AMD) and CommonJS predating ES6. The key value of having modules built in to the language is that JavaScript developers can easily consume or publish modular code under one unified module ecosystem that spans both client and server. ES6 modules feature a straightforward and imperative-style syntax, and also have a static structure that paves the way for performance optimizations and other benefits such as circular dependency support. There are times when modules need to be loaded dynamically, for example some modules might only be useful and thus loaded if certain conditions are met in execution time. For such cases, there will be a module loader which is still under discussion in the standardization committee and will be specified/ratified in the future.

ES6 Modules in Microsoft Edge

To light up ES6 modules and other experimental JavaScript features in Edge, you can navigate to about:flags and select the “Enable experimental JavaScript features” flag.

Screen capture showing the "Experimental JavaScript features" flag at about:flags

The “Experimental JavaScript features” flag at about:flags

As a first step, Edge and Chakra now support all declarative import/export syntax defined in ES6 with the exception of namespace import/export (import * as name from “module-name” and export * from “module-name”). To load modules in a page, you can use the <script type=”module”> tag. Here is an example of using a math module:

/* index.html */
...
&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;script type='module' src='./app.js'&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
...
/* app.js */
import { sum } from './math.js';
console.log(sum(1, 2));
/* math.js */
export function sum(a, b) { return a + b; }
export function mult(a, b) { return a * b; }

Implementation: static modules = faster lookup

One of the best aspects of ES6’s modules design is that all import and export declarations are static. The spec syntactically restricts all declarations to the global scope in the module body (no imports/exports in if-statement, nested function, eval, etc.), so all module imports and exports can be determined during parsing and will not change in execution.

From an implementation perspective, Chakra takes advantage of the static nature in several ways, but the key benefit is to optimize looking up values of import and export binding identifiers. In Microsoft Edge, after parsing the modules, Chakra knows exactly how many exports a module declares and what they are all named, Chakra can allocate the physical storage for the exports before execution. For an import, Chakra resolves the import name and create a link back to the export it refers to. The fact that Chakra is aware of the exact physical storage location for imports and exports allows it to store the location in bytecode and skip dynamically looking up the export name in execution. Chakra can bypass much of the normal property lookup and cache mechanisms and instead directly fetch the stored location to access imports or exports. The end result is that working with an imported object is faster than looking up properties in ordinary objects.

Going forward with modules

We have taken an exciting first step to support ES6 modules. As the experimental status suggests, the work towards turning ES6 modules on by default in Edge is not fully done yet. Module debugging in the F12 Developer Tools is currently supported in internal builds and will be available for public preview soon. Our team is also working on namespace import/export to have the declarative syntax fully supported and will look into module loader once its specification stabilizes. We also plan to add new JSRT APIs to support modules for Chakra embedders outside of Edge.

More ES6 Language Features

Microsoft Edge has led the way on a number of ES6 features. Chakra has most of ES6 implemented and on by default including the new syntax like let and const, classes, arrow functions, destructuring, rest and spread parameters, template literals, and generators as well as all the new built-in types including Map, Set, Promise, Symbol, and the various typed arrays.

In current preview builds, there are two areas of ES6 that are not enabled by default – well-known symbols and Proper Tail Calls. Well-known symbols need to be performance optimized before Chakra can enable them – we look forward to delivering this support in an upcoming Insider flight later this year.

The future of Proper Tail Calls, on the other hand, is somewhat in doubt – PTC requires a complex implementation which may result in performance and standards regressions in other areas. We’re continuing to evaluate this specification based on our own implementation work and ongoing discussions at TC39.

ES2016 & Beyond with the New TC39 Process

TC39, the standards body that works on the ECMAScript language, has a new GitHub-driven process and yearly release cadence. This new process has been an amazing improvement so far for a number of reasons, but the biggest is that it makes it easier for implementations to begin work early for pieces of a specification that are stable and specifications are themselves much smaller. As such, Chakra got an early start on ES2016 and are now shipping a complete ES2016 implementation. ES2016 was finalized (though not ratified) recently and includes two new features: the exponentiation operator and Array.prototype.includes.

The exponentiation operator is a nice syntax for doing `Math.pow` and it uses the familiar `**` syntax as used in a number of other languages. For example, a polynomial can be written like:

let result = 5 * x ** 2 – 2 * x + 5;

Certainly a nice improvement over Math.pow, especially when more terms are present.

Chakra also supports Array.prototype.includes which is a nice ergonomic improvement over the existing Array.prototype.indexOf method. Includes returns `true` or `false` rather than an index which makes usage in Boolean contexts lots easier. `includes` also handles NaN properly, finally allowing an easy way to detect if NaN is present in an array.

Meanwhile, the ES2017 specification is already shaping up and Chakra has a good start on some of those features as well, namely Object.values and entries, String.prototype.padStart and padEnd, and SIMD. We’ve blogged about SIMD in the past, though recently Chakra has made progress in making SIMD available outside of asm.js. With the exception of Object.values and entries, these features are only available with experimental JavaScript features flag enabled.

Object.values & Object.entries are very handy partners to Object.keys. Object.keys gets you an array of keys of an object, while Object.values gives you the values and Object.entries gives you the key-value pairs. The following should illustrate the differences nicely:

let obj = { a: 1, b: 2 };
Object.keys(obj);
// [ 'a', 'b' ]
Object.values(obj);
// [1, 2]
Object.entries(obj);
// [ ['a', 1], ['b', 2] ]

String.prototype.padStart and String.prototype.padEnd are two simple string methods to pad out the left or right side of a string with spaces or other characters. Not having these built-in has had some rather dire consequences recently as a module implementing a similar capability was removed from NPM. Having these simple string padding APIs available in the standard library and avoiding the additional dependency (or bugs) will be very helpful to a lot of developers.

Chakra is also previewing SIMD, with the entire API surface area in the stage 3 SIMD proposal completed, as well as a fully-optimized SIMD implementation integrated with asm.js. We are eager to hear feedback from you on how useful these APIs are for your programs.

You can try ES2015 modules and other new ES2015, ES2016, and beyond features in Microsoft Edge, starting with the latest Windows Insider Preview and share your thoughts and feedback with us on Twitter at @MSEdgeDev and @ChakraCore or on Connect. We look forward to hearing your input!

― Taylor Woll, Software Engineer
― Limin Zhu, Program Manager
― Brian Terlson, Program Manager

Previewing ES6 Modules and more from ES2015, ES2016 and beyond

Chakra, the recently open-sourced JavaScript engine that powers Microsoft Edge and Universal Windows applications, has been pushing the leading edge of ECMAScript language support.  Most of ES2015 (aka ES6) language support is already available in Edge, and last week’s Windows Insider Preview build 14342 brings more ES6 capabilities including modules, default parameters, and destructuring. We’re not stopping there – Edge also supports all ES2016 (aka ES7) proposals – the exponentiation operator and Array.prototype.includes – as well as future ECMAScript proposals such as Async Functions and utility methods like Object.values/entries and String.prototype.padStart/padEnd.

ES6 Modules

Modules let you write componentized and sharable code. Without complete support from any browser, developers have already started to get a taste of ES6 modules through transpiling from tools such as TypeScript or Babel. Edge now has early support for ES6 modules behind an experimental flag.

Modules aren’t exactly new to JavaScript with formats such as Asynchronous Module Definition (AMD) and CommonJS predating ES6. The key value of having modules built in to the language is that JavaScript developers can easily consume or publish modular code under one unified module ecosystem that spans both client and server. ES6 modules feature a straightforward and imperative-style syntax, and also have a static structure that paves the way for performance optimizations and other benefits such as circular dependency support. There are times when modules need to be loaded dynamically, for example some modules might only be useful and thus loaded if certain conditions are met in execution time. For such cases, there will be a module loader which is still under discussion in the standardization committee and will be specified/ratified in the future.

ES6 Modules in Microsoft Edge

To light up ES6 modules and other experimental JavaScript features in Edge, you can navigate to about:flags and select the “Enable experimental JavaScript features” flag.

Screen capture showing the "Experimental JavaScript features" flag at about:flags

The “Experimental JavaScript features” flag at about:flags

As a first step, Edge and Chakra now support all declarative import/export syntax defined in ES6 with the exception of namespace import/export (import * as name from “module-name” and export * from “module-name”). To load modules in a page, you can use the <script type=”module”> tag. Here is an example of using a math module:

/* index.html */
...
&lt;script type='module' src='./app.js'&gt;
...
/* app.js */
import { sum } from './math.js';
console.log(sum(1, 2));

/* math.js */
export function sum(a, b) { return a + b; }
export function mult(a, b) { return a * b; }

Implementation: static modules = faster lookup

One of the best aspects of ES6’s modules design is that all import and export declarations are static. The spec syntactically restricts all declarations to the global scope in the module body (no imports/exports in if-statement, nested function, eval, etc.), so all module imports and exports can be determined during parsing and will not change in execution.

From an implementation perspective, Chakra takes advantage of the static nature in several ways, but the key benefit is to optimize looking up values of import and export binding identifiers. In Microsoft Edge, after parsing the modules, Chakra knows exactly how many exports a module declares and what they are all named, Chakra can allocate the physical storage for the exports before execution. For an import, Chakra resolves the import name and create a link back to the export it refers to. The fact that Chakra is aware of the exact physical storage location for imports and exports allows it to store the location in bytecode and skip dynamically looking up the export name in execution. Chakra can bypass much of the normal property lookup and cache mechanisms and instead directly fetch the stored location to access imports or exports. The end result is that working with an imported object is faster than looking up properties in ordinary objects.

Going forward with modules

We have taken an exciting first step to support ES6 modules. As the experimental status suggests, the work towards turning ES6 modules on by default in Edge is not fully done yet. Module debugging in the F12 Developer Tools is currently supported in internal builds and will be available for public preview soon. Our team is also working on namespace import/export to have the declarative syntax fully supported and will look into module loader once its specification stabilizes. We also plan to add new JSRT APIs to support modules for Chakra embedders outside of Edge.

More ES6 Language Features

Microsoft Edge has led the way on a number of ES6 features. Chakra has most of ES6 implemented and on by default including the new syntax like let and const, classes, arrow functions, destructuring, rest and spread parameters, template literals, and generators as well as all the new built-in types including Map, Set, Promise, Symbol, and the various typed arrays.

In current preview builds, there are two areas of ES6 that are not enabled by default – well-known symbols and Proper Tail Calls. Well-known symbols need to be performance optimized before Chakra can enable them – we look forward to delivering this support in an upcoming Insider flight later this year.

The future of Proper Tail Calls, on the other hand, is somewhat in doubt – PTC requires a complex implementation which may result in performance and standards regressions in other areas. We’re continuing to evaluate this specification based on our own implementation work and ongoing discussions at TC39.

ES2016 & Beyond with the New TC39 Process

TC39, the standards body that works on the ECMAScript language, has a new GitHub-driven process and yearly release cadence. This new process has been an amazing improvement so far for a number of reasons, but the biggest is that it makes it easier for implementations to begin work early for pieces of a specification that are stable and specifications are themselves much smaller. As such, Chakra got an early start on ES2016 and are now shipping a complete ES2016 implementation. ES2016 was finalized (though not ratified) recently and includes two new features: the exponentiation operator and Array.prototype.includes.

The exponentiation operator is a nice syntax for doing `Math.pow` and it uses the familiar `**` syntax as used in a number of other languages. For example, a polynomial can be written like:

let result = 5 * x ** 2 – 2 * x + 5;

Certainly a nice improvement over Math.pow, especially when more terms are present.

Chakra also supports Array.prototype.includes which is a nice ergonomic improvement over the existing Array.prototype.indexOf method. Includes returns `true` or `false` rather than an index which makes usage in Boolean contexts lots easier. `includes` also handles NaN properly, finally allowing an easy way to detect if NaN is present in an array.

Meanwhile, the ES2017 specification is already shaping up and Chakra has a good start on some of those features as well, namely Object.values and entries, String.prototype.padStart and padEnd, and SIMD. We’ve blogged about SIMD in the past, though recently Chakra has made progress in making SIMD available outside of asm.js. With the exception of Object.values and entries, these features are only available with experimental JavaScript features flag enabled.

Object.values & Object.entries are very handy partners to Object.keys. Object.keys gets you an array of keys of an object, while Object.values gives you the values and Object.entries gives you the key-value pairs. The following should illustrate the differences nicely:

let obj = { a: 1, b: 2 };
Object.keys(obj);
// [ 'a', 'b' ]
Object.values(obj);
// [1, 2]
Object.entries(obj);
// [ ['a', 1], ['b', 2] ]

String.prototype.padStart and String.prototype.padEnd are two simple string methods to pad out the left or right side of a string with spaces or other characters. Not having these built-in has had some rather dire consequences recently as a module implementing a similar capability was removed from NPM. Having these simple string padding APIs available in the standard library and avoiding the additional dependency (or bugs) will be very helpful to a lot of developers.

Chakra is also previewing SIMD, with the entire API surface area in the stage 3 SIMD proposal completed, as well as a fully-optimized SIMD implementation integrated with asm.js. We are eager to hear feedback from you on how useful these APIs are for your programs.

You can try ES2015 modules and other new ES2015, ES2016, and beyond features in Microsoft Edge, starting with the latest Windows Insider Preview and share your thoughts and feedback with us on Twitter at @MSEdgeDev and @ChakraCore or on Connect. We look forward to hearing your input!

― Taylor Woll, Software Engineer
― Limin Zhu, Program Manager
― Brian Terlson, Program Manager

Asynchronous code gets easier with ES2016 Async Function support in Chakra and Microsoft Edge

While we work on rounding out our ES6/ES2015 support, the Chakra team is already looking ahead to ES2016 and, especially, to Async Functions. Today, we’re excited to announce the availability of Async Functions in Microsoft Edge as an experimental feature, available to preview starting in Microsoft Edge (EdgeHTML 13.10547).

ES7/ES2016 Async Functions

The async and await keywords, part of the Async Functions proposal, provide an easy way to write asynchronous code. It is one of the killer features of C# and is often requested by JavaScript developers.  Before Async Functions and Promises, a JavaScript developer had to carve out all the asynchronous code she needed into a separate function from the synchronous core and use callbacks to retrieve the result of the asynchronous computation. This code can quickly become hard to read and difficult to maintain.

ES6 Promises helped improve the way to write asynchronous code by standardizing and by including the feature directly in the web browser. But it did not totally solve the problem as we still need to use callbacks to retrieve the result.

Async Functions are based on Promises, but take them a step further. When you add an async keyword to a function or an arrow function it will automatically return a Promise. For example, the following code is a standard ES2015 program that performs an Http request with promises:

.gist table { margin-bottom: 0; }

If we rewrite the same code and get the same behavior with Async Functions, the result is smaller and more readable code. The code below also has a refactoring to change the way we manage the error in the function:

.gist table { margin-bottom: 0; }

The async keyword also works with ES6 arrow functions, simply by adding the keyword before the arguments. Following in an example of the same:

.gist table { margin-bottom: 0; }

To clarify:

  • Use the async keyword with any function declaration or arrow function to get asynchronous code with a Promise. This includes functions in classes and static function. For this last one, the async keyword should be placed after the static keyword and before the function’s name.
  • Use the await keyword to make execution wait for the end of an async expression (a call to an async function for example) and get the returned value of the Promise.
  • If you don’t use the await keyword, you will get a Promise.
    .gist table { margin-bottom: 0; }

  • You cannot use the await keyword outside an async function, including the global scope.

How is it implemented in Chakra?

In a previous post, we discussed the architecture of the Chakra engine in detail using the diagram below. The parts requiring the most modification to support Async Functions are highlighted in green.

Global behavior

Using the async keyword will generate a Promise constructor, according to the specifications, that wraps the function’s body. To perform this action, Chakra’s Bytecode Generator generates a call to a built-in function that describe the following behavior:

.gist table { margin-bottom: 0; }

The spawn function above is designed to manage all the async expressions in the function’s body and decide to stop or continue the process depending of the behavior inside the async function. If an async expression called with an await keyword fails, for example because of an error inside the async function or something being awaited, the promise will be rejected to make it possible to manage the error higher in the stack.

Now the engine needs to make the JS script call this spawn function to get the Promise and run the function’s body. To do this, when the parser detects an async keyword, the engine changes the AST (Abstract Syntax Tree), which represents the developer’s algorithm, to add a call to the Spawn function with the function’s body. Consequently, the httpGetJson function is converted like this by the parser:

.gist table { margin-bottom: 0; }

Note the use of Generators and the yield keyword to perform the await keyword’s behavior. Indeed, the implementation of the await keyword is extremely similar to the yield keyword.

Behavior with a default argument

One of the new feature from ES6 is the possibility to set a default value to an argument in a function. When default value is set, the Bytecode Generator will set the value at the top of the function’s body.

.gist table { margin-bottom: 0; }

In the case of an async keyword, if the default value sets to this argument throw an error, the specifications ask to reject a Promise. This allows the exception to be caught easily.

To realize it, the Chakra team had two choices: change the AST (Abstract Syntax Tree), or implement it directly in the Bytecode Generator. We chose to implement it directly in the Bytecode Generator by moving the argument’s initialization to the top of the function’s body directly in the Bytecode, because it is an easier and cleaner solution in this engine. Since a try/catch needs to be added to intercept any error from the argument’s default value, it’s easier to change the Bytecode directly when we detect an async keyword.

Finally, the generated Bytecode will be similar to what would be generated for the following JavaScript code:

.gist table { margin-bottom: 0; }

How to enable Async Functions in Microsoft Edge?

To enable and experiment with the current Async Functions support in Microsoft Edge, navigate to about:flags in Microsoft Edge and select the “Enable experimental JavaScript features” flag as below:

Screen capture showing the "Experimental JavaScript features" flag at about:flags

The “Experimental JavaScript features” flag at about:flags

Async Functions are available to preview via the Windows Insider Program starting in Microsoft Edge 13.10547.We can’t wait to hear about how you will be using the feature in your ES2016 code and look forward to sharing more soon about our next investments in Chakra. In the meantime, feel free to join the comment discussion, reach out on Twitter @MSEdgeDev, or on Connect.

Etienne Baudoux, Software Development Engineer Intern, Chakra Team
Brian Terlson, Senior Program Manager, Chakra Team