ECMAScript proposal, specs, tests, and reference implementation for Asynchronous locks
This initial proposal was drafted by @johnhenry with input from @_ and @_.
Designated TC39 reviewers: @_ @_
- Table of Contents
- Status
- Prior Art
- Rationale and Motivation
- Proposed Solution: Asynchronous Blocks
- other operators
- for/for-in/for-of
- for-await-fo
- while
- do
- other operators
- Specification
- Transformation
This proposal is currently at stage 0 of the process.
Some of the syntaxes in this proposal, namely the "do await" syntax, have been discussed before
Previously, in order to preform a one-off task within a program that didn't affect the global scope, one had to use an Immediately Invoked Function Expression (IIFE).
(function(){consta=1;console.log(a);//other stuff...})();(function(){consta=2;console.log(a);//other stuff...})();//logs "1", "2";With blocks and blocked scoped variables, introduced for 2015, the syntax becomes much cleaner.
{consta=1;console.log(a);//other stuff}{consta=2;console.log(a);//other stuff}console.log(a);//logs "1", "2";Currently if we want to invoke as asynchronous expression, set to be introduced for 2017 we must resort to using an IIFE once more.
(asyncfunction(){consta=awaiteventually(1);//other stuff...})();(asyncfunction(){consta=awaiteventually(2);//other stuff...})();//logs eventually "1", "2" or "2", "1"Alternatively, we can use non-anoymous functions and invoke them later in the program:
constmain=asyncfunction(){consta=awaiteventually(1);//other stuff...};constmain2=asyncfunction(){consta=awaiteventually(2);//other stuff...}main();main2();//logs eventually "1", "2" or "2", "1"but this is still not as elegant as one might hope.
We can make this cleaner by implementing asynchronous blocks
async{consta=awaiteventually(1);console.log(a);//other stuff}async{consta=awaiteventually(2);console.log(a);//other stuff}//logs eventually "1", "2" or "2", "1"Asynchronous blocks are executed asynchronously with respect to the surrounding context and allow use of the "await" keyword without having to create another functional scope.
This would work in conjunctions with other operators that come before blocks:
constfor(constiof[1,2])async{awaiteventually(i);}console.log(0);//logs "0"//logs eventually "1", "2"See Asynchronous Iterator Proposal
async{forawait(constiofeventuallyIterator(1,2))async{console.log(i);}console.log(0);}//logs "0"//logs eventually "1", "2"while(true)async{awaiteventually(i++);}console.log(0);//logs "0"//logs eventually "1", "2"...constresult=doasync{consta=1;}result.then(console.log.bind(console));//logs eventually "1"When Number.prototype[Symbol.iterator] is called, the following steps are taken:
- While parsing, if the keyword "async" is encountered directly before a block, execute that block's contents asynchronously with respect to the surrounding program.
- That block will now have the "await" keyword available at the top level.
- Declarations using keywords "let" and "const" would not affect the scope outside of the asynchronous block.
- Keeping in mind backward compatibility, declarations using the keyword "var", along with naked declarations, would affect the scope outside of the asynchronous block.
The following transformation recursively on a string:
constmatch=/^async\s*{\s*(.*)\s*}/m;constwrap=(code)=>`(async function(){${code}})()`;exportdefault(code)=>{returnmatch.test(code) ? wrap(code.match(match)[1]) : code;};would have the following result:
async { ... } -> (asyncfunction(){ ... })()Although, it misses the requirement regarding "backward compatibility" above in that it does not respect the use of the "var" keyword.