Friday, April 29, 2016

ES6, ES7, and beyond

The V8 team places great importance on the evolution of JavaScript into an increasingly expressive and well-defined language that makes writing fast, safe, and correct web applications easy. In June 2015, the ES6 specification was ratified by the TC39 standards committee, making it the largest single update to the JavaScript language. New features include classes, arrow functions, promises, iterators / generators, proxies, well-known symbols, and additional syntactic sugar. TC39 has also increased the cadence of new specifications and released the candidate draft for ES7 in February 2016, to be ratified this summer. While not as expansive as the ES6 update due to the shorter release cycle, ES7 notably introduces the exponentiation operator and Array.prototype.includes().

Today we’ve reached an important milestone: V8 supports ES6 and ES7. You can use the new language features today in Chrome Canary, and they will ship by default in the M52 release of Chromium.

Given the nature of an evolving spec, the differences between various types of conformance tests, and the complexity of maintaining web compatibility, it can be difficult to determine when a certain version of ECMAScript is considered fully supported by a JavaScript engine. Read on for why spec support is more nuanced than version numbers, why proper tail calls are still under discussion, and what caveats remain at play.

An evolving spec

When TC39 decided to publish more frequent updates to the JavaScript specification, the most up-to-date version of the language became the master, draft version. Although versions of the ECMAScript spec are still produced yearly and ratified, V8 implements a combination of the most recently ratified version (e.g. ES6), certain features which are close enough to standardization that they are safe to implement (e.g. the exponentiation operator and Array.prototype.includes() from the ES7 candidate draft), and a collection of bug fixes and web compatibility amendments from more recent drafts. Part of the rationale for such an approach is that language implementations in browsers should match the specification, even if the it’s the specification that needs to be updated. In fact, the process of implementing a ratified version of the spec often uncovers many of the fixes and clarifications that comprise the next version of the spec.

Currently shipping parts of the evolving ECMAScript specification

For example, when implementing the ES6 RegExp sticky flag, the V8 team discovered that the semantics of the ES6 spec broke many existing sites (including all sites using versions 2.x.x of the the popular XRegExp library on npm). Since compatibility is a cornerstone of the web, engineers from the V8 and Safari JavaScriptCore teams proposed an amendment to the RegExp specification to fix the breakage, which was agreed upon by TC39. The amendment won't appear in a ratified version until ES8, but it's still a part of the ECMAScript language and we've implemented it in order to ship the RegExp sticky flag.

The continual refinement of the language specification and the fact that each version (including the yet-to-be-ratified draft) replaces, amends, and clarifies previous versions makes it tricky to understand the complexities behind ES6 and ES7 support. While it's impossible to state succinctly, it's perhaps most accurate to say that V8 supports compliance with the “continually maintained draft future ECMAScript standard”!

Measuring conformance

In an attempt to make sense of this specification complexity, there are a variety of ways to measure JavaScript engine compatibility with the ECMAScript standard. The V8 team, as well as other browser vendors, use the test262 test suite as the gold standard of conformance to the continually maintained draft future ECMAScript standard. This test suite is continually updated to match the spec and it provides 16,000 discrete functional tests for all the features and edge cases which make up a compatible, compliant implementation of JavaScript. Currently V8 passes approximately 98% of test262, and the remaining 2% are a handful of edge cases and future ES features not yet ready to be shipped.

Since it’s difficult to skim the enormous number of test262 tests, other conformance tests exist, such as the Kangax compatibility table. Kangax makes it easy to skim to see whether a particular feature (like arrow functions) has been implemented in a given engine, but doesn’t test all the conformance edge cases that test262 does. Currently, Chrome Canary scores a 98% on the Kangax table for ES6 and 100% on the sections of Kangax corresponding to ES7 (e.g. the sections labelled “2016 features” and “2016 misc” under the ESnext tab).

The remaining 2% of the Kangax ES6 table tests proper tail calls, a feature which has been implemented in V8, but deliberately turned off in Chrome Canary due to outstanding developer experience concerns detailed below. With the “Experimental JavaScript features” flag enabled, which forces this feature on, Canary scores 100% on the entirety of the Kangax table for ES6.

Proper Tail Calls

Proper tail calls have been implemented but not yet shipped given that a change to the feature is currently under discussion at TC39. ES6 specifies that strict mode function calls in tail position should never cause a stack overflow. While this is a useful guarantee for certain programming patterns, the current semantics have two problems. First, since the tail call elimination is implicit, it can be difficult for programmers to identify which functions are actually in tail call position. This means that developers may not discover misplaced attempted tail calls in their programs until they overflow the stack. Second, implementing proper tail calls requires eliding tail call stack frames from the stack, which loses information about execution flow. This in turn has two consequences:
  1. It makes it more difficult to understand during debugging how execution arrived at a certain point since the stack contains discontinuities and
  2. Error.prototype.stack contains less information about execution flow which may break telemetry software that collects and analyzes client-side errors.
Implementing a shadow stack can improve the readability of call stacks, but the V8 and DevTools teams believe that debugging is easiest, most reliable, and most accurate when the stack displayed during debugging is completely deterministic and always matches the true state of the actual virtual machine stack. Moreover, a shadow stack is too expensive performance-wise to turn on all the time.

For these reasons, the V8 team strongly support denoting proper tail calls by special syntax. There is a pending TC39 proposal called syntactic tail calls to specify this behavior, co-championed by committee members from Mozilla and Microsoft. We have implemented and staged proper tail calls as specified in ES6 and started implementing syntactic tail calls as specified in the new proposal. The V8 team plans to resolve the issue at the next TC39 meeting before shipping implicit proper tail calls or syntactic tail calls by default. You can test out each version in the meantime by using the V8 flags --harmony-tailcalls and --harmony-explicit-tailcalls.


One of the most exciting promises of ES6 is support for JavaScript modules to organize and separate different parts of an application into namespaces. ES6 specifies import and export declarations for modules, but not how modules are loaded into a JavaScript program. In the browser, loading behavior was recently specified by the new <script type="module"> tag. Although additional standardization work is needed to specify advanced dynamic module-loading APIs, Chromium support for module script tags is already in development. You can track implementation work on the launch bug and read more about experimental loader API ideas in the whatwg/loader repository.

ESnext and beyond

In the future, developers can expect ECMAScript updates to come in smaller, more frequent updates with shorter implementation cycles. The V8 team is already working to bring upcoming features such as async / await keywords, Object.values() / Object.entries(), String.prototype.padStart() / String.prototype.padEnd() and RegExp lookbehind to the runtime. Check back for more updates on our ESnext implementation progress and performance optimizations for existing ES6 and ES7 features.

We strive to continue evolving JavaScript and strike the right balance of implementing new features early, ensuring compatibility and stability of the existing web, and providing TC39 implementation feedback around design concerns. We look forward to seeing the incredible experiences developers will build with these new features.

-- Posted by the V8 team, ECMAScript Enthusiasts


  1. My favorite new part of the ES7 spec, not mentioned here, is a mechanism for capturing unhandled Promise rejections like uncaught errors. In ES6, errors in asynchronous code just disappear into the ether. ES7 (and the HTML Living Standard) fixes that via the unhandledrejection event, which is like window.onerror for promises.

    And V8 and Chrome do now support unhandledrejection. :)

    1. Where is this defined in the spec? I couldn't find it in the ES2015 promises spec.

    2. It's split between two standards because it involves both JavaScript and DOM events.

      The underlying behavior is defined in ES2016:

      The unhandledrejection event is the HTML DOM method of exposing that feature, so that's in the HTML Living Standard:

      Node meanwhile uses process.on("unhandledRejection", handler):

  2. This is great!

    Regarding ECMAScript 5 (yes, that old thing), kangax lists three features (and one strict mode feature and one nonstandard feature) that are not supported in Chrome. Were all of them dropped from future editions of ECMAScript?

    Also, a small correction -
    but deliberated turned off in Chrome Canary
    Should be -
    but deliberately turned off in Chrome Canary

  3. Object.prototype.values() / Object.prototype.entries() should be Object.values() / Object.entries()

  4. This comment has been removed by a blog administrator.

  5. chrome v8 has been the most important open source project since the launch of java, until the oracle buy thanks in good time

  6. Kudos to the V8 folks for making all these magics happen. We can only hope that a day will come when we no longer need to use some sort of transpiler/shim to support ECn, ECn-1, ..., EC3, IE9, IE8...

  7. This makes me wonder: if all major browser vendor agree that syntactic tail calls are preferable over implicit tail calls, how could they make it into ES6?
    IMHO, tail calls shouldn't have been included in the already crammed-with-features ES6 and deferred to ES7 in the first place, especially since it was already clear back then (afaik) that there will be shorter release cycles. Then there would have been time for engines to experiment with tail calls and raise potential issues *before* standardization.

  8. When you say "ship by default in the M52 release of Chromium", does that mean they will be behind a feature flag, or strict mode or whatever? Also, from the mentioned featured, are none of them supported already in M50?

    1. They are enabled by default as specced modulo the topics mentioned in the post. Those are accessible behind a flag.

  9. Slowly enhance your self till you're Exoslim standing for your ft, then slowly lower yourself down till you're standing flat again. This is simple however very powerful. Doing those exercises way which you have taken all the steps to a.For more ==== >>>>>>

  10. Best proper food regimen assist you to Hydro Muscle Max achieve your goals with the proper sporting events. Following most of these suggestions will assist you build up a very good and healthy body. precise success.when you are at domestic and also.For more ==== >>>>>>

  11. You're talking about test262 conformance... But do you know that Chrome/chromium from 49 up to canary 55 are unable to finish test262's latests versions? Stuck at around 30% currently...

    1. Possibly ?