diff --git a/run.js b/run.js index 74b1a93..f3997f0 100644 --- a/run.js +++ b/run.js @@ -5,15 +5,20 @@ function run(generator, callback) { var iterator = generator(resume); var data = null, yielded = false; - var next = callback ? nextSafe : nextPlain; - + if (!callback) callback = function (err) { + // If the generator ended with an error, throw it globally with setTimeout. + // Throwing locally from a callback is not allowed, and swallowing the + // error is a bad idea, so there's no better option. + if (err) setTimeout(function () { throw err; }, 0); + }; + next(); check(); - function nextSafe(item) { + function next(err, item) { var n; try { - n = iterator.next(item); + n = (err ? iterator.throw(err) : iterator.next(item)); if (!n.done) { if (typeof n.value === "function") n.value(resume()); yielded = true; @@ -25,13 +30,6 @@ function run(generator, callback) { } return callback(null, n.value); } - - function nextPlain(item) { - var cont = iterator.next(item).value; - // Pass in resume to continuables if one was yielded. - if (typeof cont === "function") cont(resume()); - yielded = true; - } function resume() { var done = false; @@ -49,8 +47,7 @@ function run(generator, callback) { var item = data[1]; data = null; yielded = false; - if (err) return iterator.throw(err); - next(item); + next(err, item); yielded = true; } } diff --git a/test.js b/test.js index 32bde81..fa5eaa0 100644 --- a/test.js +++ b/test.js @@ -70,7 +70,7 @@ function *run_with_callback(gen) { console.log("Callback"); yield run(function* (gen) { yield sleep(1000); - return "Hello" + return "Hello"; }, function (err, value) { console.log("Callback err: " + err); console.log("Callback value: " + value); @@ -102,7 +102,25 @@ function *run_with_callback_early_exception(gen) { console.log("Callback value: " + value); gen()(null, value); // Intentionally suppress the error }); - console.log("End"); + testRun("run_with_thrown_error", run_with_thrown_error); +} + +function *run_with_thrown_error(gen) { + var inCatch = false; + try { + yield sleep(1); + yield fail(); + console.error("this should not happen!"); + } + catch (err) { + console.log("in catch: " + err); + console.assert(err); + inCatch = true; + } + yield sleep(1); + console.log("yielded after catch"); + console.assert(inCatch); + console.log("\nEnd"); } function sleep(ms) { @@ -117,7 +135,13 @@ function evil() { setTimeout(function () { callback(null, 2); }, 100); - } + }; +} + +function fail() { + return function (callback) { + callback(Error("throwing error into generator")); + }; } function decrement(n) {