-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Async Functions #1664
Comments
This proposal looks great. Really looking forward to having this in TypeScript as asynchrony is so important, yet such a pain, in the JS world. I'm glad to see you're planning on supporting ES3/ES5 with async as well. |
I've added a section on promise implementation compatibility. |
Still thinking about the proposal. One super nitpicky request off the top: is it possible to use human-readable variable names in the generator code instead of single letters? An optimiser needs to run over all code anyway for production, and will take care of shortening variables, so this is just obfuscation. When users examine code to understand and learn things, it will be much easier for them to understand what is going on with proper variable names. (This is an issue with the default generated |
How are failed or rejected promises handled with this proposal? I guess you'd need to handle them with try/catch? |
@bgever, that is correct. In an Async Function you could change from writing this: function logCommits(): Promise<void> {
var client = new HttpClient();
return client.getAsync('https://github.com/Microsoft/TypeScript/commits/master.atom').then(
response => {
console.log(response.responseText);
},
error => {
console.log(error);
});
} To this: async function logCommits(): Promise<void> {
var client = new HttpClient();
try {
var response = await client.getAsync('https://github.com/Microsoft/TypeScript/commits/master.atom');
console.log(response.responseText);
}
catch (error) {
console.log(error);
}
} This also allows for more complex async logic that is harder to achieve with async function poll(): Promise<void> {
do {
var dataReady = await isDataReadyAsync();
} while (!dataReady);
} |
Thanks for the quick response. Something interesting in your first example is that there's no need to What I dislike about the catch clause, is that you can't use the functional programming way of just passing the function. E.g: Would it be useful to have an inline option as well? function errorHandler(e) { /* handle */ }
//---or---
var errorHandler = (e) => { /* handle */ }; // Handle errors inline without the need to wrap with try{}.
var result = await myAsync() catch errorHandler;
//---or---
var result = await myAsync() catch e => {
/* handle */
} The var result = await myAsync() catch async e => { // `async` inline catch returns promise
if(/*can't recover*/){
throw new Error('Cannot recover');
}
return 'fallback value';
}
//---or---
var result = await myAsync() catch async e => /*can't recover*/ ? throw new Error('Cannot recover') : 'fallback value'; |
Looks good - I agree with the variable naming suggestion by @csnover |
@bgever, some Promise implementations, such as the native implementation in ES6, have a var result = await myAsync().catch(errorHandler);
//---or---
var result = await myAsync().catch(e => {
// ...
}); |
👍 |
@rbuckton, ah, of course! As long as we feed a Promise to await - including chained ones - it should work. Thanks for pointing that out. |
If I understand correctly, await is part of ES7 specification and async is part of ES6 specification. I will be happy if TypeScript support await as a make-up wrapper for ES6 because ES6 been long, long overdue and nobody wanna wait for ES7 to come out. We have been patiently waiting and still stuck waiting for most web browser products to start supporting ES7 & ES6. http://www.joezimjs.com/javascript/synchronizing-asynchronous-javascript-es7/ |
Actually,
|
Here is the ES7 proposal: |
What if the instruction string constants ("next", "throw", ...) are replaced by using properties from the following object: var __instruction = {
next: 0,
throw: 1,
return: 2,
yield: 3,
yieldstar: 4,
break: 5,
endfinally: 6
} This would make the generated code more minification and obfuscation friendly, whilst at the same time keeping the unminified code readable. For example, the following: // async.js
var __awaiter = /* ... */;
var __generator = /* ... */;
function fn() {
var i;
return new Promise(function (_resolve) {
resolve(__awaiter(__generator(function (_state) {
switch (_state.label) {
case 0: return ["yield", p0];
case 1:
i = _state.sent;
return ["yield", p1];
case 2:
return ["return", _state.sent + i];
}
}));
});
} Would become: // async.js
var __awaiter = /* ... */;
var __generator = /* ... */;
var __instruction = /* ... */;
function fn() {
var i;
return new Promise(function (_resolve) {
resolve(__awaiter(__generator(function (_state) {
switch (_state.label) {
case 0: return [__instruction.yield, p0];
case 1:
i = _state.sent;
return [__instruction.yield, p1];
case 2:
return [__instruction.return, _state.sent + i];
}
}));
});
} |
+1 for compiling ES7 async/await to ES6 yield/Promise/__awaiter -1 for ES5 and ES3 state-machine emits. I think those are better served with dedicated projects like regenerator instead of bundling into the TS compiler and duplicating effort. |
I disagree, I'd rather have TS have this built in instead of forcing me to compile ALL my code to |
@basarat Supporting class inheritance is a tiny rewrite compared to the state-machine rewrite that supporting generators requires. That's why I don't think tsc should take the burden of supporting downlevel emit for generators. See regenerator's code for yourself and see how complicated the rewrite is. |
@Arnavion I've seen you write much more complex algorithms (this is me praising your awesome code skills). |
@masammut I think a better alternative may be to use integer literals, so where you see "yield" today, we might replace it with |
Again, let me emphasize the difference between supporting downlevel emit for this vs something like inheritance. The inheritance support is two parts, the __extends function and the places where it's called. The places where it's called is a simple function call, and the __extends function itself is overridable by client code. For generators, the two parts are the __generator function and the state machine that it drives. The latter is vastly more complicated than a function call ala class inheritance and is not overridable. If it has a bug, you're stuck with it until it's fixed in the next version of TS. If you encounter a bug in TS's emit for destructuring, you can just not use destructuring. If you encounter a bug in TS's emit for yield, you have to either implement a state machine yourself to minimize change in the generator's callers, or change that function and every caller to a different design (callbacks, etc.) The generated state machine has to handle conditionals, loops, exceptions, jump labels, ... everything that affects flow control. See the history of the regenerator code I linked, and the referenced bugs and test cases, and think about whether you'd want to report such bugs to TS. The latest fix is less than 2 weeks old, and there are still open issues, so it's by no means a completely solved problem. I have no doubt the TS team can implement a rewriter that can fix all those known problems and pass all current tests. The question is: Is this something they should spend time on implementing, and then spend time on maintaining? We already have traceur and regenerator (6to5 also uses regenerator, as I just discovered) with their own pluses and minuses (traceur supports all of ES6, regenerator has a better codegen and uses esprima). Do we really need a third that only works with TS? (It would be awesome that TS supported such a downlevel emit by using regenerator, but this is prevented of course by TS not depending on node to run.) |
If memory serves the CoffeeScript guys refused to take a PR that covered similar ground. The result was a fork of the project called Iced CoffeeScript: http://maxtaco.github.io/coffee-script/ I'm not sure if es5 / es3 support is worth the trouble because of the debugging story. I value the TS being not too different from the JS. It wouldn't be in this case and so even if available it would probably be a feature I chose not to use with es3 / es5 |
For es3 & 5, it might be cleaner to use a callback based emit instead of a state machine? I think an emit like this would be a lot cleaner & more readable: // TypeScript
var p0: Promise<number> = /* ... */;
var p1: Promise<number> = /* ... */;
async function fn() {
var i = await p0;
return await p1 + i;
}
// JavaScript
function fn() {
var i;
return Promise.resolve(void 0).then(_a);
function _a() {
return p0.then(_b);
}
function _b(value) {
i = value;
p1.then(_c);
}
function _c(value) {
return value + i;
}
}
// TypeScript
var p0: Promise<number> = /* ... */;
var p1: Promise<number> = /* ... */;
async function fn() {
try {
await p0;
}
catch (e) {
if (foo) return 42;
if (bar) return await p1;
alert(e.message);
if (baz) {
await p1;
}
}
finally {
await p1;
}
}
// JavaScript
function __asyncTryCatch(_try, _catch, _finally) {
Promise.resolve(void 0).then(_try).then(_finally, function(err) {
return Promise.resolve(_catch(err)).then(function(value) { // value: [boolean, T | Promise<T>]
if (value[0]) { // return
return value[1]; // Can be Promise<T> or T.
} else {
// value[1] can be Promise<T> or T, so we need te convert it to Promise<T>
return Promise.resolve(value[1]).then(_finally);
}
}, function(err) {
Promise.resolve(_finally()).then(function() {
throw err;
});
});
});
}
function fn() {
return Promise.resolve(void 0).then(_a);
function _a() {
return __asyncTryCatch(_b, _c, _d).then(_e);
}
function _b() {
return p0;
}
function _c(e) {
if (foo) return [true, 42];
if (bar) return [true, p2];
alert(e.message);
if (baz) {
return [false, p1];
}
return [false, void 0];
}
function _d() {
return p1;
}
function _e() {
return void 0;
}
}
// TypeScript
async function fn() {
var data = await bar(1);
if (data.foo) {
console.log(await bar(2));
console.log(await bar(3));
}
for (var i = 0; i < 10; i++) {
await bar(4);
}
return data;
}
// JavaScript
function fn() {
var data, i, dataObj;
return Promise.resolve(void 0).then(_a); // Start in a Promise context, since a Promise catches errors
function _a() {
return bar(1).then(_b);
}
function _b(value) {
data = value;
if (data.foo) {
return bar(2).then(_c);
}
return _e();
}
function _c(value) {
console.log(value);
return bar(3).then(_d);
}
function _d(value) {
console.log(value);
return _e();
}
function _e() { // Code after the 'if' is wrapped in a function, otherwise it would be emitted twice.
i = 0;
return _f();
}
function _f() {
if (i < 10) {
return bar(4).then(_g);
}
return data;
}
function _g() {
i++;
return _f();
}
} A function will be cut in smaller functions. This way there are no nested callback needed. Advantages:
|
The original proposal is for emitting generators in general, not just async-await, so it can't rely on Promises. Generators are synchronous whereas a Promise never resolves synchronously. Also, your alternative emit is equivalent to the proposed state machine:
If it's a matter of readability, you could apply the same transformation for the generator state machine. Just move each case-block to its own closure, and make each closure return a reference to the next closure to call instead of the label of the next state (i.e., instead of |
I totally misunderstood the question, which is about support for async/await in the typescript compiler. I have no insight into that at all |
@MatAtBread @jamiewinder As @mhegazy mentioned, TypeScript 1.7+ has support for |
Do not underestimate the sway of legacy environments. |
@RichiCoder1 I know! I've been there, but I guess as a community we have always felt IE drags us down. That's changing with Microsoft officially deprecating older IE. The support for generators is pretty good at this point. Only IE 11 and Safari lag behind. I know this is still a significant audience, especially with Enterprise but looking over the above discussion, the Cost - benefit analysis of But hey that's just my personal opinion. I'd be really happy if this happens! :) |
Sorry for closing the issue and not leaving a comment. async/awiat support in the type system and for ES6 target was done in 1.7, and enabled by default with no flags. |
@mhegazy Is there a way to disable async/await transformation only? (if I'm targetting Node.js chakra only and don't want this extra step with wrappers) |
No, issue #4692 tracks more fine grained control over transformations. |
@saschanaz @jods4 For the "typing issue", you can always explicitly declare arity: module Promise {
function all<T1>(promises: [T1|Thenable<T1>]): Promise<[T1]>;
function all<T1, T2>(promises: [T1|Thenable<T1>, T2|Thenable<T2>]): Promise<[T1, T2]>;
function all<T1, T2, T3>(promises: [T1|Thenable<T1>, T2|Thenable<T2>,
T3|Thenable<T3>]): Promise<[T1, T2, T3]>;
function all<T1, T2, T3, T4>(promises: [T1|Thenable<T1>, T2|Thenable<T2>,
T3|Thenable<T3>, T4|Thenable<T4>]): Promise<[T1, T2, T3, T4]>;
function all<R>(promises: (R | Thenable<R>)[]): Promise<R[]>;
// ... to whatever is reasonable
} |
Async function support for target ES3/ES5 is now available in |
For people interested in how does the output look like currently I've put a gist here: https://gist.github.com/wiktor-k/eed3ef8032f73caba33d4fd1ddd16308 Is there a plan to use async/await -> ES5 transformation similar to kneden? The output looks a lot simpler there. The TS approach looks like it would be easier to extend to support generators too. |
@wiktor-k I don't quite agree kneden looks simpler. For the trivial Note that in your gist, Have you looked at how kneden translates a function test() {
return Promise.resolve().then(function () {
return Promise.resolve().then(function () {
return db.destroy();
}).catch(function (err) {
return Promise.resolve().then(function () {
console.log(err);
return db.post({});
}).then(function (_resp) {
console.log(_resp);
});
}).then(function () {
return db.info();
}, function (_err) {
return Promise.resolve().then(function () {
return db.info();
}).then(function () {
throw _err;
});
});
}).then(function () {});
} Personally, I much prefer the As soon as there is complex control flow (loops, try, etc) using Another important aspect -- but I might be wrong here -- is that it's hard to guarantee kneden supports all valid JS code and produces correct code (homepage says "it tries"). Notably, at this point it doesn't support |
I don't know kneden, but nodent https://github.com/MatAtBread/nodent does implement all JS constructs containing Disclaimer: I'm the author of nodent. |
@MatAtBread I had a look at your project and I was very impressed! 👏 I noticed the following in the playground, though. It seems to me that when using Promises the following ES7 code generates ES5 code that results in recursive calls of arbitrary depth (in this case, the ES5 looks like it will nest 3'000'000 function calls, i.e. 3 per loop iteration). async function x() {
for (let i = 0; i < 1000000; i++) {
if (i == 999999) await a;
}
} Turning loop iterations into recursive calls has serious drawbacks. If I am right, I think this makes it not ok for a widely used compiler like TS. |
You're quite right about loops without tall-recursion. There's a discussion of the issue in MatAtBread/fast-async#11 The solution (the one I use in almost ask my production code) is to use Promises over pure-ES5 mode. |
... actually, I've only just understood your case - it only awaits rarely. That's a good one, I might try and handle that one differently to avoid the recursion, since that code path doesn't need it. Thanks for the input! |
@jods4 - Inspired as I was by your comment above, I (finally) implemented loops using a sync/async trampoline. Performance isn't too bad, since I at least avoid creating Promises and turning ticks if the loop doesn't yield. A long loop (see link below) is around 1.2s on my mac in ES5-eager, 2.8s with native Promises, and 3.1s with generators/Promises. Those numbers are only a rough guide as a lot of factors are not easy to control for in the browser. More reliable results are available from the command line. I've not released nodent v3 yet as I'm still testing, but I updated the playground for testing. |
@matAtWork nice work. I was curious how you'd solve it! |
Probably not the place to spend ages on it, but JS is the proof that "premature optimization is the root of all evil". In particular, a lot of performance hits on older JS engines have been heavily fixed - closures are a perfect example (now almost as fast as object dereferencing), and Promises are, well, promising. When I started Nodent almost 3 years ago, avoiding Promises was a very easy win (Nodent only used callbacks). Since then, Promise implementations have been honed down, and the JS engines are much better at identifying and optimizing pinch points, so the benefits of avoiding them have fallen. I'm guessing the same will be true of generators, although it's not there yet - right now they're still 3x-4x slower. Meanwhile, the kind of transforms Nodent does really are pretty much what everyone in Node-land does by hand (identifying common code to put in functions and pass as callbacks), of which there is so much around I'm sure the engine writers have squeezed lots of performance out of it. |
Now that this is added how does one await an array of promises? I have a ton of ng.IPromise and I want to execute them all at the same time and then await them all completing. |
`const arrayOfResults = await Promise.all(arrayOfPromises);`
…On Thu, Dec 8, 2016 at 9:31 AM, James Hancock ***@***.***> wrote:
Now that this is added how does one await an array of promises? I have a
ton of ng.IPromise and I want to execute them all at the same time and then
await them all completing.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1664 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAhETMg1gVWQ9Amq2PARpYv_Pmlsq07Gks5rGCLUgaJpZM4DSFLM>
.
--
Brandon Wallace
Senior Architect, Expero Inc.
@bman654 | experoinc.com | 832-312-7294
|
Also handy: const [a, b, c] = await Promise.all([Promise.resolve(1), Promise.resolve(true), Promise.resolve('a')]);
// a is number, b is boolean, c is string |
Promise.all doesn't seem to work with ng.IPromise so I'm using $q.all right now which sadly isn't strongly typed on the results. I was hoping that there was a better way. |
@JohnGalt1717 That's weird, it should work judging from |
Async Functions
1 Async Functions
This is a spec proposal for the addition of Async Functions (also known as
async..await
) as a feature of TypeScript.2 Use Cases
Async Functions allow TypeScript developers to author functions that are expected to invoke an asynchronous operation and await its result without blocking normal execution of the program. This accomplished through the use of an ES6-compatible
Promise
implementation, and transposition of the function body into a compatible form to resume execution when the awaited asynchronous operation completes.This is based primarily on the Async Functions strawman proposal for ECMAScript, and C# 5.0 § 10.15 Async Functions.
3 Introduction
3.1 Syntax
An Async Function is a JavaScript Function, Parameterized Arrow Function, Method, or Get Accessor that has been prefixed with the
async
modifier. This modifier informs the compiler that function body transposition is required, and that the keywordawait
should be treated as a unary expression instead of an identifier. An Async Function must provide a return type annotation that points to a compatiblePromise
type. Return type inference can only be used if there is a globally defined, compatiblePromise
type.Example:
3.2 Transformations
To support this feature, the compiler needs to make certain transformations to the function body of an Async Function. The type of transformations performed depends on whether the current compilation target is ES6, or ES5/ES3.
3.2.1 ES6 Transformations
During compilation of an Async Function when targeting ES6, the following transformations are applied:
await
expressions inside the original function body are transformed into a compatibleyield
expression.yield
is much lower thanawait
, it may be necessary to enclose theyield
expression in parenthesis if it is contained in the left-hand-side of a binary expression.__awaiter
helper function.__awaiter
helper function is passed as an argument to the promise resolve callback.Example:
3.2.2 ES5/ES3 Transformations
As ES5 and earlier do not support Generator Functions, a more complex transformation is required. To support this transformation,
__generator
helper function will be also emitted along with the__awaiter
helper function, and a much more comprehensive set of transformations would be applied:__generator
helper function.await
expression is rewritten into flattened set of instructions that are interpreted by the__generator
helper function.await
expression are rewritten to preserve shortcutting.await
are rewritten to store portions left-hand side of the assignment in temporary locals to preserve side effects.await
in the argument list are rewritten to store the callee and this argument, and to instead call thecall
method of the callee.await
in the argument list are rewritten to preserve side effects.await
in the element list are rewritten to preserve side effects.await
in the element list are rewritten to preserve side effects.__generator
helper function.catch
clause is renamed to a unique identifier and all instances of the symbol are renamed to preserve the block scope behavior of a catch variable.break
andcontinue
statements whose target is a statement that contains anawait
expression are rewritten to return an instruction interpreted by the__generator
helper function.return
statements are rewritten to return an instruction interpreted by the__generator
helper function.for..in
statements that contain anawait
expression are rewritten to capture the enumerable keys of the expression into a temporary array, to allow the iteration to be resumed when control is returned to the function following anawait
expression.await
expression are rewritten.await
expressions are rewritten to return an instruction interpreted by the__generator
helper function.Example:
The following is an example of an async function that contains a
try
statement:As a result of these transformations, the JavaScript output for an Async Function can look quite different than the original source. When debugging the JavaScript output for an Async Function it would be advisable to use a Source Map generated using the
--sourceMap
option for the compiler.4 Promise
Async Functions require a compatible Promise abstraction to operate properly. A compatible implementation implements the following interfaces, which are to be added to the core library declarations (lib.d.ts):
The following libraries contain compatible Promise implementations:
A Grammar
A.1 Types
CallSignature [Await,AsyncParameter] :
TypeParameters opt
(
ParameterList [?Await,?AsyncParameter]opt)
TypeAnnotation opt*ParameterList_ [Await,AsyncParameter] *:_
RequiredParameterList [?Await]
OptionalParameterList [?Await,?AsyncParameter]
RestParameter [?Await]
RequiredParameterList [?Await]
,
OptionalParameterList [?Await,?AsyncParameter]RequiredParameterList [?Await]
,
RestParameter [?Await]OptionalParameterList [?Await,?AsyncParameter]
,
RestParameter [?Await]RequiredParameterList [?Await]
,
OptionalParameterList [?Await,?AsyncParameter],
RestParameter [?Await]RequiredParameterList [Await] :
RequiredParameter [?Await]
RequiredParameterList [?Await]
,
RequiredParameter [?Await]RequiredParameter [Await] :
AccessibilityModifier opt BindingIdentifier [?Await] TypeAnnotation opt
Identifier
:
StringLiteralOptionalParameterList [Await,AsyncParameter] :
OptionalParameter [?Await,?AsyncParameter]
OptionalParameterList [?Await,?AsyncParameter]
,
OptionalParameter [?Await,?AsyncParameter]OptionalParameter [Await,AsyncParameter]:
[+AsyncParameter] AccessibilityModifier opt BindingIdentifier [Await]
?
TypeAnnotation opt[+AsyncParameter] AccessibilityModifier opt BindingIdentifier [Await] TypeAnnotation opt Initialiser [In]
[+AsyncParameter] BindingIdentifier [Await]
?
:
StringLiteral[~AsyncParameter] AccessibilityModifier opt BindingIdentifier [?Await]
?
TypeAnnotation opt[~AsyncParameter] AccessibilityModifier opt BindingIdentifier [?Await] TypeAnnotation opt Initialiser [In,?Await]
[~AsyncParameter] BindingIdentifier [?Await]
?
:
StringLiteralRestParameter [Await]:
...
BindingIdentifier [?Await] TypeAnnotation optA.2 Expressions
BindingIdentifier [Await] : ( Modified )
Identifier but not
await
[~Await]
await
PropertyAssignment [Await] :
PropertyName
:
AssignmentExpression [?Await]PropertyName CallSignature
{
FunctionBody}
GetAccessor
SetAccessor
async
[no LineTerminator here] PropertyName CallSignature [Await,AsyncParameter]{
FunctionBody [Await]}
GetAccessor :
get
PropertyName(
)
TypeAnnotationopt{
FunctionBody}
async
[no LineTerminator here]get
PropertyName(
)
TypeAnnotation opt{
FunctionBody [Await]}
FunctionExpression [Await] : ( Modified )
function
BindingIdentifier [?Await]opt CallSignature{
FunctionBody}
async
[no LineTerminator here]function
BindingIdentifier [?Await]opt CallSignature [Await,AsyncParameter]{
FunctionBody [Await]}
AssignmentExpression [Await] : ( Modified )
...
ArrowFunctionExpression [?Await]
ArrowFunctionExpression [Await] :
ArrowFormalParameters
=>
Block [?Await]ArrowFormalParameters
=>
AssignmentExpression [?Await]async
[no LineTerminator here] CallSignature [Await,AsyncParameter]=>
Block [Await]async
[no LineTerminator here] CallSignature [Await,AsyncParameter]=>
AssignmentExpression [Await]ArrowFormalParameters [Await] :
CallSignature
BindingIdentifier [?Await]
UnaryExpression [Await] : ( Modified )
...
<
Type>
UnaryExpression [?Await][+Await]
await
UnaryExpression [Await]A.3 Functions
FunctionDeclaration [Await] : ( Modified )
FunctionOverloads [?Await]opt FunctionImplementation [?Await]
FunctionOverloads [Await] :
FunctionOverloads [?Await]opt FunctionOverload [?Await]
FunctionOverload [Await] :
function
BindingIdentifier [?Await] CallSignature;
FunctionImplementation [Await] :
function
BindingIdentifier [?Await] CallSignature{
FunctionBody}
async
[no LineTerminator here]function
BindingIdentifier [?Await] CallSignature [Await,AsyncParameter]{
FunctionBody [Await]}
A.4 Classes
MemberFunctionImplementation:
AccessibilityModifieropt
static
opt PropertyName CallSignature{
FunctionBody}
AccessibilityModifieropt
static
optasync
[no LineTerminator here] PropertyName CallSignature [Await,AsyncParameter]{
FunctionBody [Await]}
B Helper Functions
There are two helper functions that are used for Async Functions. The
__awaiter
helper function is used by both the ES6 as well as the ES5/ES3 transformations. The__generator
helper function is used only by the ES5/ES3 transformation.B.1
__awaiter
helper functionB.2
__generator
helper functionB.2.1
_generator
Argumentsm
B.2.2
n
Argumentsc
B.2.3 Variables
d
i
f
g
s.trys
stack.s
s.label
s.trys
try..catch..finally
blocks.s.sent
next
.s.error
catch
clause.y
b
n
to execute for the current instruction. One of"next"
,"throw"
, or"return"
.B.2.4 Instructions
0 /*next*/
1 /*throw*/
catch
orfinally
blocks.2 /*return*/
finally
blocks.3 /*yield*/
4 /*yield**/
5 /*break*/
finally
blocks if the target is outside of the current protected region.6 /*endfinally*/
finally
block so that the previousbreak
,throw
, orreturn
instruction can be processed.B.2.5 Protected Regions
A protected region marks the beginning and end of a
try..catch
ortry..finally
block. Protected regions are pushed onto thes.trys
stack whenever a protected region is entered when executing the state machine. A protected region is defined using a quadruple in the following format:try
block.catch
block.finally
block.try..catch..finally
block.B.3
__generator
helper function (alternate)The text was updated successfully, but these errors were encountered: