Tail Call Optimization implementation in Javascript Engines

As of February 2019 in Chrome Version 71.0.3578.98 on Mac
, the following program throws Uncaught RangeError: Maximum call stack size exceeded error. at a count of 16516.

const a = x => {
  a(x + 1)


I’ve done quite a bit of Googling, but wasn’t able to find any articles discussing Chrome or other browser support for Tail Call Optimization (TCO) or any future plans to implement it.

My two questions are:

  1. Is TCO currently supported in Chrome or any other browser or Javascript Engine
  2. Are there plans to implement TCO in the near future in any Javascript Engine

The posts that I’ve found are mostly old (2016 or earlier) or simply confusing. e.g. https://www.chromestatus.com/feature/5516876633341952

TCO, or rather, Tail Call Elimination in JavaScript — also often referred to as Proper Tail Calls (PTC) in discussions — is a long and sad story.

Around 2011, TC39 (the JavaScript standards committee) decided to adopt mandatory TCE for the forthcoming ES6 standard, with consensus from all major browser vendors.

In 2015, the new standard was officially adopted, under the name EcmaScript 2015. At this point, no browser had actually implemented TCE, mostly because there were too many new features in ES2015 that were deemed more important to get out. (Today’s process for JS feature proposals and their adoption, which includes the requirement of two implementations in production engines, did not yet exist for ES6.)

In early 2016, both Safari and Chrome implemented TCE. Safari announced shipping it, while Chrome kept it behind an Experimental Feature flag. Other browsers (Firefox and Internet Explorer / Edge) started looking into it as well and had second thoughts. Discussion evolved whether this is a viable feature after all. Edge had problems implementing it efficiently for the Windows ABI, Firefox was concerned about the developer experience of calls “missing” from stack traces (an issue that was already discussed at length in 2011).

Read More:   ReactJS call parent method

In an attempt to address some of these concerns while rescuing the tail call feature, several members, including the Chrome and Edge teams, proposed to make tail calls explicit, i.e., require return statements to be annotated with an additional keyword to opt into tail call semantics. These so-called “syntactic tail calls” (STC) were implemented in Chrome as a proof of concept.

At the May 2016 TC39 meeting the issue of tail calls was discussed extensively for almost an entire day with no resolution. Firefox and Edge made clear that they would not implement TCE as specified in the standard. Firefox members proposed to take it out. Safari and Chrome did not agree with that, and the Safari team made clear that they have no intention of unshipping TCE. The proposal for syntactic tail calls was rejected as well, especially by Safari. The committee was in an impasse. You can read the meeting notes of this discussion.

Technically, this impasse still exists today, as far as I am aware. Practically speaking, though, tail calls for JavaScript are pretty much dead, and it’s unclear whether they will ever come back. At least that was the conclusion of the Chrome team after the disastrous meeting, which led to the decision to remove the implementation of tail calls from Chrome, in order to simplify the engine and prevent bit rot. They are still available in Safari.

Disclosure: I was a member of TC39 and of the Chrome/V8 team until 2017, so my views may be biased.

Read More:   Detect timezone abbreviation using JavaScript

Even tho TCO seems to be a pipe dream for all of us, by using a trampoline technique, you can easily convert your code to run as if it is being tail optimized.

const a = x => {
  if(x > 500000) {
  return ()=> a(x + 1); //you return a function, it hasn't been called yet

const trampoline = fn => (...args) => {
  let result = fn(...args)
  //repeatedly call the function till you hit your base case
  while (typeof result === 'function') {
    result = result();
  return result;

var t = trampoline(a);

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts