Permalink
Browse files

fixed a bug preventing yield/resume after catching a thrown error

  • Loading branch information...
1 parent a71479a commit 6f125714caf45cc8776698d5889e1d10b8c8803a @jmar777 committed Nov 27, 2013
Showing with 30 additions and 27 deletions.
  1. +12 −27 lib/suspend.js
  2. +18 −0 test/general.js
View
@@ -98,7 +98,7 @@ Suspender.prototype.start = function start(ctx, args) {
}
this.iterator = this.generator.apply(ctx, args);
- this.next();
+ this.nextOrThrow();
};
/**
@@ -120,16 +120,17 @@ Suspender.prototype.handleYield = function handleYield(ret) {
};
/**
- * Calls `.next()` on the iterator, and ensures that yielded values and thrown
- * errors will be properly handled. Also helps keep track of whether or not we
- * are resumed synchronously.
+ * Calls `.next()` or `.throw()` on the iterator, depending on the value of the
+ * `isError` flag. This method ensures that yielded values and thrown errors
+ * will be properly handled, and helps keep track of whether or not we are
+ * resumed synchronously.
*/
-Suspender.prototype.next = function next(val) {
+Suspender.prototype.nextOrThrow = function next(val, isError) {
this.syncResume = true;
activeSuspender = this;
- var res;
+ var ret;
try {
- res = this.iterator.next(val);
+ ret = isError ? this.iterator.throw(val) : this.iterator.next(val);
} catch (err) {
if (this.callback) {
return this.callback(err);
@@ -141,23 +142,7 @@ Suspender.prototype.next = function next(val) {
activeSuspender = null;
}
// everything was ok, so keep going
- this.handleYield(res);
-};
-
-/**
- * Calls `.throw()` on the iterator, ensuring that if the error isn't handled
- * within the generator, it is caught and handled correctly.
- */
-Suspender.prototype.throwError = function throwError(err) {
- try {
- this.iterator.throw(err);
- } catch (err) {
- if (this.callback) {
- return this.callback(err);
- } else {
- throw err;
- }
- }
+ this.handleYield(ret);
};
/**
@@ -172,15 +157,15 @@ Suspender.prototype.resume = function resume(err, result) {
if (this.rawResume) {
this.rawResume = false;
- this.next(Array.prototype.slice.call(arguments));
+ this.nextOrThrow(Array.prototype.slice.call(arguments));
} else {
if (this.done) {
throw new Error('Generators cannot be resumed once completed.');
}
- if (err) return this.throwError(err);
+ if (err) return this.nextOrThrow(err, true);
- this.next(result);
+ this.nextOrThrow(result);
}
};
View
@@ -45,6 +45,19 @@ describe('suspend(fn*)', function() {
})(yield asyncDouble(num));
})(5);
});
+
+ it('should support continuing execution after a handled error', function(done) {
+ suspend(function* (num) {
+ var doubled = yield asyncDouble(num);
+ try {
+ yield asyncError();
+ } catch (err) {
+ // ignore
+ }
+ assert.strictEqual(28, yield asyncDouble(doubled));
+ done();
+ })(7);
+ });
});
// async functions used for test cases
@@ -53,3 +66,8 @@ function asyncDouble(x) {
setTimeout(function() { deferred.resolve(x * 2); }, 20);
return deferred.promise;
}
+function asyncError() {
+ var deferred = Q.defer();
+ setTimeout(function() { deferred.reject(new Error('fail')); }, 20);
+ return deferred.promise;
+}

0 comments on commit 6f12571

Please sign in to comment.