Last active
August 29, 2015 13:56
-
-
Save thomasboyt/9286079 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A restartable promise chain using q (tho it could be adapted for other libs). | |
* | |
* Usage: | |
* var chain = new RestartableChain([firstFn, secondFn, thirdFn...]); | |
* | |
* chain.execute() - run chain, returning a promise that is resolved if all promises | |
* in the chain resolve, otherwise rejects at first rejection. | |
* | |
* If the chain has been previously run & errored, this method will restart from the | |
* function that rejected. | |
* i.e, if secondFn rejects, then rerunning chain.execute() will run secondFn and thirdFn | |
*/ | |
var q = require('q'); | |
var RestartableChain = function(fns) { | |
this.fns = fns; | |
this.fnIndex = 0; | |
}; | |
RestartableChain.prototype._next = function() { | |
var idx = this.fnIndex; | |
if ( idx >= this.fns.length ) { | |
this.dfd.resolve(this.lastPayload); | |
return; | |
} | |
this.fns[idx](this.lastPayload).then(function(payload) { | |
this.fnIndex += 1; | |
this.lastPayload = payload; | |
this._next(); | |
}.bind(this), function(err) { | |
this.dfd.reject(err); | |
}.bind(this)); | |
return this.dfd.promise; | |
}; | |
RestartableChain.prototype.execute = function() { | |
// reset the promise | |
this.dfd = q.defer(); | |
return this._next(); | |
}; | |
module.exports = RestartableChain; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var assert = require('assert'); | |
var q = require('q'); | |
var RestartableChain = require('../index'); | |
describe('Restartable chain', function() { | |
/* | |
* Stubs | |
*/ | |
var oneCalled, twoCalled, errCalled, didError; | |
var one = function() { | |
oneCalled += 1; | |
var dfd = q.defer(); | |
dfd.resolve(); | |
return dfd.promise; | |
}; | |
var two = function() { | |
twoCalled += 1; | |
var dfd = q.defer(); | |
dfd.resolve('success'); | |
return dfd.promise; | |
}; | |
var err = function() { | |
errCalled += 1; | |
var dfd = q.defer(); | |
if ( !didError ) { | |
dfd.reject('error'); | |
didError = true; | |
} else { | |
dfd.resolve('success'); | |
} | |
return dfd.promise; | |
}; | |
beforeEach(function() { | |
oneCalled = 0; | |
twoCalled = 0; | |
errCalled = 0; | |
didError = false; | |
}); | |
it('calls each fn in the chain', function(done) { | |
var chain = new RestartableChain([one, two]); | |
chain.execute().done(function(payload) { | |
assert.equal(chain.fnIndex, 2); | |
assert.equal(payload, 'success'); | |
done(); | |
}); | |
}); | |
it('can resume from a rejected handler', function(done) { | |
var chain = new RestartableChain([one, err]); | |
var makeRequest = function() { | |
chain.execute().done(function(payload) { | |
assert.equal(oneCalled, 1); | |
assert.equal(errCalled, 2); | |
assert.equal(payload, 'success'); | |
assert.equal(didError, true); | |
done(); | |
}, function(err) { | |
assert.equal(err, 'error'); | |
makeRequest(); | |
}); | |
}; | |
makeRequest(); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment