Last active
August 29, 2015 14:02
-
-
Save ofstudio/ee6b6c92bf0c35fb8c01 to your computer and use it in GitHub Desktop.
Javascript Deferred / Promise pattern
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 simple workaround on Deferred / Promise pattern | |
* with result caching and multiply actions on success / fail | |
* | |
* defer() returns methods: | |
* resolve(data) - request is successfully resolved (returns nothing) | |
* reject(msg) - request if failed (returns nothing) | |
* promise() - returns promise function | |
* | |
* promise() returns methods: | |
* done(successfulCallback) - add on successful callback (returns nothing) | |
* fail(failCallback) - add on fail callback (returns nothing) | |
* always(alwaysCallback) - add always callback (returns nothing) | |
* | |
* Example: | |
* | |
* function someHeavyRequest(url) { | |
* var d = defer(); | |
* doHeavyRequest(url, | |
* function (data) { | |
* // on success | |
* // ...do something | |
* d.resolve(data); | |
* }, | |
* function (data) { | |
* // on fail | |
* // ...do something | |
* d.reject(data); | |
* }); | |
* return d.promise(); | |
* } | |
* | |
* var req = someHeavyRequest("http://some.url/of/request/"); | |
* | |
* req.done(function (data) { | |
* console.log("We got it!"); | |
* console.log(data); | |
* }); | |
* | |
* req.done(function (data) { | |
* console.log("We got it again without new request!"); | |
* console.log(data); | |
* }); | |
* | |
* req.fail(function (data) { | |
* console.error("Something wrong"); | |
* console.error(data); | |
* }); | |
* | |
* req.always(function (data) { | |
* console.log("Whatever happens..."); | |
* console.log(data); | |
* }); | |
* | |
* Thanx to Flambino for code review | |
* http://codereview.stackexchange.com/questions/54143/ | |
* | |
* @returns {{promise: promise, resolve: resolve, reject: reject, always: always}} | |
*/ | |
function defer() { | |
var currentState = 'pending', | |
callbacks = { resolved: [], rejected: [], always: [] }, | |
args = []; | |
function execute(state) { | |
var cb; | |
while(callbacks[state].length) { | |
cb = callbacks[state].shift(); | |
if( typeof cb === 'function' ) cb.apply(cb, args); | |
} | |
} | |
// generic function factory for done/fail functions | |
function handle(state) { | |
return function (cb) { | |
callbacks[state].push(cb); | |
if(currentState !== 'pending') { | |
if(currentState === state) execute(state); | |
if(state === 'always') execute('always'); | |
} | |
} | |
} | |
// generic function factory for resolve/reject functions | |
function complete(state) { | |
return function () { | |
if(currentState !== 'pending') return; | |
args = Array.prototype.slice.call(arguments, 0); | |
currentState = state; | |
execute(state); | |
execute('always'); | |
} | |
} | |
return { | |
promise: function () { | |
return { | |
done: handle('resolved'), | |
fail: handle('rejected'), | |
always: handle('always') | |
}; | |
}, | |
resolve: complete('resolved'), | |
reject: complete('rejected') | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment