A handful of proposals are already at that stage. And you can get an idea of what other features may make it into ECMAScript 2022 by looking at which have reached stage three, where the spec has been signed off and the tests have been passed. But these proposals need to be tried out in an implementation to see how well they actually work in practice.
“If you’re running a module initializer — the top level of your code that runs when your module begins — that hasn’t always been regarded as asynchronous,” Palmer said.
Using the await function to wait on an asynchronous process as that top-level might result in a syntax error if other code tries to read results that haven’t yet been returned, and attempts to avoid that by using async main make code more complicated and harder to test or perform static analysis on.
It’s taken a while for Top-Level Await to become part of ECMAScript because of concerns that it would make it more likely that developers would create deadlocks in their code.
“When we allow asynchronous operations to be put in there, people can write arbitrarily long-running operations — like querying a database, making a network request,” Palmer warned.
“If you are not careful with this feature, you could delay your entire app loading. You can’t even run the first main function because you’re now waiting on some arbitrary operation to complete.”
But calling async code is very common in browsers, he added, because if you have to wait for a piece of code to finish running before anything else can run, blocking code can cause performance issues.
With Top-Level Await, ECMAScript is diverging from Node.js, which uses CommonJS modules, which will remain synchronous for backward compatibility. Developers won’t be able to load ECMAScript modules synchronously in a CommonJS file; they should use the dynamic import operator, which returns not the module but a promise for the module, loading it asynchronously.
Finally, Private Fields
Discussions about implementing private fields have gone on for a number of years (and they’re already available in Node.js). The suite of proposals that make up the new class fields is ready to be part of ECMAScript 2022, with a mix of proposals for public, private and static fields, methods and accessors, including a way to check if a private field exists.
All the browsers are now implementing key pieces. Being able to declare instances of static fields and make them private for data encapsulation has already been implemented in Chrome and Safari.
That unlocked the key proposals going to stage four earlier this year, according to Palmer.
Temporal is a global object that will be a top-level namespace for the new date and time API, covering the full range of date, time, time zones, calendars and even public holidays.
Whether you need the current time, a Unix timestamp, the day of the week a date falls on in a particular year, how many days till Christmas, whether a business that lists opening hours is open or closing in the next few minutes, an easy way to sort dates and times or something more complex involving multiple time zones, the Temporal API covers it.
Going from a single Date object to multiple options in Temporal may feel like more work, but Terlson suggested it will be easier to use in practice because it’s more rigorous.
“The Date object that we have now only feels easy because you don’t realize you’re shooting yourself in the foot half a dozen times,” he said. “The new date system forces you to think about that complexity upfront, and so you’re just frontloading your bug-finding efforts.
“Dates are one of those things where it’s hard to test; you can’t just change the system date easily in the middle of unit tests,” he added, “The right way to do it is to mock it — but a lot of people just don’t touch their date code so they don’t find [the problems.”
In addition, Terlson said, “you almost need to be a data expert to know what the interesting test cases are.” Not every developer would think to test for leap year behavior or what if their code will run correctly when a leap second is declared, he suggested. “Or a mobile app when the user changes time zone — is it going to fall over?”
Palmer calls Temporal “in some ways the least controversial proposal” he’s seen. Everyone wants to see it progress, he noted — but because it’s such a large API, fully implementing and testing it and taking feedback may take a little time.
However, production-quality polyfills are already in development, and there’s a sandbox in the Temporal documentation powered by an earlier polyfill, so developers can try it out in their browser developer tools.
He also sees strong developer demand and expects Temporal to start getting used quickly, so developers can remove Moment.js from their applications, “making everyone’s code lighter and faster to download.” But the sheer size of the API means testing will take time.
“The reason these libraries are so big and complex is not accidental complexity,” Palmer said. “It is because the rules in our world for dates and times are so complex that you want to offload as much as much as you can to the experts that have thought about this and embedded all that knowledge in the API.”
Moving Temporal to stage four will also have to wait until the Internet Engineering Task Force (IETF) work to standardize the string formats used for calendar and time zone annotations is complete; that’s expected for 2022.
Chaining Error Cause
Also at stage three is a proposal Terlson views as a companion to the aggregate error that was standardized with Promise.any in ECMAScript 2021: Error Cause, which is already implemented in Chrome, Firefox, Safari and Node.js.
“Aggregate error is used for cases when you have different sources of errors: where you’re doing different processes and you get a bunch of errors that are only related by the fact that they are kicked off by the same activity,” Terlson said.
The Error Cause proposal is a way to link errors that cause other errors, like making a network request as part of a bigger operation that will use that network request. Often developers will just throw an error if the network request fails, which doesn’t provide any context for which operation failed because of the network request failure.
With Error Cause, developers can throw an error including an error code with a cause property that records how many requests filed, each of which has its own error with more information, and those can chain more errors in turn.
“It lets you catch an error and throw an error with more context, while preserving the original error,” Terlson said.
There are also some interesting proposals that have only reached stage two —where there’s a full specification and it’s likely the proposal will continue to be developed and become part of ECMAScript, but there’s not enough agreement to sign off a complete specification that’s ready to be tested in implementations.
Record and Tuple for Better Matching
Tuple data structures easier to debug.
Record is similar to a frozen object and
Tuple is similar to a frozen array,” Palmer said. Because they’re primitives rather than objects (which have identity) and they’re compared by value, you can compare two separate objects that contain the same things – like a person’s name – and they’ll be recognized as being the same, even though they’re in different objects, each of which has its own identity.
If you’re using that name as the key to a map, you want to be able to do a lookup in some other part of your code, where you generate a fresh record but want to find out if that person’s name is in the map. With Record and Tuple, you’ll get the match instead of it failing because the fresh record is a brand new identity object.
“Previously, people had to do tricks to try and make maps work well when you want to use a composite key with multiple things, like serializing the contents into a string with special markers between the different fields, so that the strings would be compared by value,” Palmer said.
Reading the contents of an object out into a string is an opportunity to introduce bugs; now you can use proper language structures and use the regular triple
=== equality comparison.
This will be particularly useful for comparisons in JSON-style deep object trees, Palmer suggested. “You’re getting a more semantic style of equality.”
=== can also improve performance and reduce the compute load of rendering the user interface.
“A common functional pattern, like you see in React, is where you’re examining your data properties, and seeing how they changed since the last render,” Palmer said. “You can do optimizations: if my input data has not changed, I would expect the rendering map remains identical, so you don’t need to recompute it.”
He views the syntax as less cumbersome than the existing libraries: “This provides a really, terse, really clear way of dealing with immutable data structures. Also, if you’re a library writer, you now have a common currency to exchange with the rest of the world. It standardizes the way of passing around immutable data.”
Pipeline Operator Still in the Pipeline
Some other interesting proposals are less likely to make the ECMAScript 2022 timeline.
Most scripting environments have a pipeline operator that lets you take the output of one function and “pipe” it into another function (pipes are also widely used in functional programming). Without a pipe operator, you have to build a hierarchy of nested functions which can be hard to read, or create — and manage — temporary intermediate variables to store and pass results from function to function.
The Hack-style proposal has reached stage 2 and there are already plugins for Babel and a feature flag in Firefox that support the new operator, but there are also ongoing discussions about concerns on the impact on browser engine memory and performance, so the pipe operator is still definitely experimental and seems unlikely to be in ECMAScript 2022.