The ES6 method: iterator.throw(err)
is often described as injecting an exception as though it occurred at the yield
statement in the generator. The problem is that the stack trace for this exception does not contain any reference to the file/line for the yield statement or even the function that it is in. Rather, the stack trace seems to only be generated when the exception object is constructed, which is not inside the generator
.
The question is: how can I get the location of the offending yield statement, in a stack trace or otherwise?
function* one_of_many_generators() {
// ...
yield ajax(url); // <-- what I need in the stack trace
// ...
}
function outer() {
var iterator = one_of_many_generators();
iterator.next(); // runs to the first yield
// inject exception at the yield statement
iterator.throw(Error("error")); // <-- top of stack trace shows here
}
Though this issue is not specific to Promises
, they may make it easier to picture the problem. In my case, I am using a task system with generators and promises. The hypothetical function ajax()
returns a Promise, and if that is rejected then the error is converted into a throw at the yield statement using this mechanism.
The stack traces in the debugger are pretty useless because I cannot find a way to get the function, file, or line number for the yield statement
where this injection is occurring. Calling iterator.throw(err)
is treated like a rethrow, and does not get new stack information, so it only shows a location inside the ajax()
function which can be called from many places, and by throwing a new error in outer()
like in the example above, the same throw line shows for all errors. Neither gives a hint as to what generator
function was being executed for debugging the error.
I am using Chrome v42.
Iterators and promises don't mix very well (yet) - you're essentially yielding a promise that then fails outside the loop.
You can get round this by passing the results of the promise back to the generator, something like:
function* one_of_many_generators() {
// ...
var promiseResult = yield ajax(url); // <-- what I need in the stack trace
// Now we're back in the generator with the result of the promise
if(notHappyWithResult(promiseResult))
throw new Error('Reason result is bad');
// ...
}
async function outer() {
var iterator = one_of_many_generators();
let prms = iterator.next(); // runs to the first yield
// Wait for the promise to finish
let result = await prms;
// Pass the result back to the generator
let whatever = iterator.next(result);
}
Only: this is kind of what async
and await
do anyway (these keywords being just syntactic sugar for a generator of promises with results passed back) and if you use them a regular try-catch
will work.
iterator.throw
is mainly a way of stopping the iteration, not injecting an exception back into it - top of the stack is still wherever you create the Error
.
Finally, coming soon in Chrome are async iterators - these are pretty powerful and are all about iterations of promises.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With