Created
March 14, 2018 10:13
-
-
Save peta/c4f80ab081db6ef21707277674f93d44 to your computer and use it in GitHub Desktop.
Some random examples showing simple JavaScript Promise usage patterns, I wrote together during a frontend dev course I gave back in 2015
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
// Example 1 -- Prom-what??!# | |
//===== Callback-style | |
// Nested async foo as we know and love it | |
// Output from previous async call becomes input of the one called next | |
giveBirthTo(function (peter) { | |
growUp(peter, function (grownUpPeter) { | |
travelTheWorld(grownUpPeter, function (culturedPeter) { | |
marryAndHaveKids(culturedPeter, function (seniorPeter) { | |
liveHappyUntilEndOfLife(seniorPeter, function (lifeExperience) { | |
console.log(lifeExperience); | |
restart(); | |
}); | |
}); | |
}); | |
}); | |
}); | |
//===== Promise-style | |
// Equivalent using promise chain | |
var lifeOfPeter = giveBirthTo() | |
.then(growUp) | |
.then(travelTheWorld) | |
.then(marryAndHaveKids) | |
.then(liveHappyUntilEndOfLife) | |
.then(function (lifeExperience) { | |
console.log(lifeExperience); | |
restart(); | |
}); | |
// A Promise could also be passed around everywhere in your code and once resolved, | |
// all subsequent calls to "then()" will immediately (=SYNC) return the actual (=resolved) data value | |
// Just retrieve the actual value our Promise was resolved with | |
var lifeExperience = lifeOfPeter.then(function (lifeExperience) { | |
return lifeExperience; | |
}); | |
// Apply functional composition logic to our already resolved Promise (could also be simplyfied by "Promise#filter()") | |
var petersHolidaysInEurope = lifeOfPeter | |
.then(function filterOutHolidays (lifeExperience) { | |
return lifeExperience.filter(function (experience) { | |
return experience.isTypeOf('holiday'); | |
}) | |
}) | |
.then(function filterOutEuropeanDestinations (holidays) { | |
return holidays.filter(function (h) { | |
return h.destination.country === 'Europe'; | |
}); | |
}); |
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
// Example 2 -- Just some simple application init code | |
//===== Callback-style | |
function initMyApp (onInit, onError) { | |
loadLocalization(function (locStrings) { | |
// Localized strings loaded | |
createDataSource(function (error, ds) { | |
if (error) { | |
onError('DataSource creation failed'); | |
return; | |
} | |
jQuery(document).ready(function () { | |
var myGridElem = jQuery('#myGrid'); | |
// Finally initialize the grid | |
initMyGrid(myGridElem, ds, function () { | |
// We're done | |
onInit(); | |
}); | |
}); | |
}); | |
}, function () { | |
// Some error occured | |
onError('Error while loading localized strings'); | |
}); | |
} | |
initMyApp(function () { | |
// Initialized | |
jQuery('#loading').hide(); | |
}, function (error) { | |
// Error occured | |
jQuery('#loading').hide(); | |
alert(error); | |
}); | |
//===== Promise-style | |
// Equivalent using promise aggregation, chaining and one error handler for all | |
Promise.all([ | |
loadLocalization(), | |
createDataSource(), | |
onDomReady() | |
]) | |
.then(initMyGrid) | |
.then(function () { | |
// All previous steps are finished | |
jQuery('#loading').hide(); | |
}) | |
.catch(function (error) { | |
// Error occured | |
jQuery('#loading').hide(); | |
alert(error); | |
}); |
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
// Example 3 -- Cascaded Grid DataSource initialization (pattern as used by XYZ) | |
//===== Callback-style | |
function initDataSources () { | |
// init attribute datasource | |
attributionGrid.operation.initAttributeDataSource(function(attributeDataSource) { | |
// init global property | |
attributionGrid.setAttributeDataSource(attributeDataSource); | |
// init contact datasource | |
attributionGrid.operation.initContactDataSource(function(contactDataSource) { | |
// init global property | |
attributionGrid.setContactDataSource(contactDataSource); | |
// init attribution datasource | |
attributionGrid.operation.initAttributionDataSource(function(attributionDataSource) { | |
// init global property | |
attributionGrid.setAttributionDataSource(attributionDataSource); | |
// init attribution key value pair datasource | |
attributionGrid.operation.initKeyValuePairDataSource(function(keyValuePairDataSource) { | |
// init global property | |
attributionGrid.setKeyValuePairDataSource(keyValuePairDataSource); | |
// init attribution key value pair suggestion datasource | |
attributionGrid.operation.initKeyValuePairSuggestionDataSource(function(keyValuePairSuggestionDataSource) { | |
// init global property | |
attributionGrid.setKeyValuePairSuggestionDataSource(keyValuePairSuggestionDataSource); | |
try { | |
// init callback | |
if ($.isFunction(callback)) { | |
callback(); | |
} | |
} | |
catch(error) { | |
attributionGrid.log.error(error); | |
} | |
}); | |
}); | |
}); | |
}); | |
}); | |
}; | |
//===== Promise-style | |
// Promise-based equivalent when the DataSource aren't dependant on each each other (e.g. on the previous one) | |
Promise.props({ | |
attributes: initAttributeDataSource(), | |
contacts: initContactDataSource(), | |
attributions: initAttributionDataSource(), | |
keyValues: initKeyValueDataSource(), | |
kvSuggestions: initKeyValuePairSuggestionDataSource() | |
}).then(function (dataSources) { | |
attributionGrid.setDataSources(dataSources); | |
// Invoke callback when all DataSources were initialized and ready to use | |
// We don't have to care whether an exception will be thrown somewhere since we | |
// attached an error-handler later on which will event catch asynchronously thrown exceptions | |
if ($.isFunction(callback)) { | |
callback(); | |
} | |
}).error(function (error) { | |
attributionGrid.log.error(error); | |
}); | |
// Promise-based equivalent when the DataSources depend on each other | |
// - We infer dependencies through outer->inner wrapping from original callback-style code | |
// - We expect that every datasource init function takes the previously created ds as first parameter | |
initAttributeDataSource() | |
.then(initContactDataSource) | |
.then(initAttributionDataSource) | |
.then(initKeyValueDataSource) | |
.then(initKeyValuePairSuggestionDataSource) | |
.then(function (dataSources) { | |
attributionGrid.setDataSources(dataSources); | |
// Invoke callback when all DataSources were initialized and ready to use | |
// We don't have to care whether an exception will be thrown somewhere since we | |
// attached an error-handler later on which will event catch asynchronously thrown exceptions | |
if ($.isFunction(callback)) { | |
callback(); | |
} | |
}).catch(function () { | |
// Handler gets called when one promise of our chain gets rejected (for what reason ever) | |
// We could also add a specialized handler as second parameter to "then(onResolve, onReject)" | |
// in order to deal with an eventual rejection especially for the current step | |
alert('Not all DataSources could be initialized'); | |
}) | |
.error(function (error) { | |
// Our application threw some exception | |
attributionGrid.log.error(error); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment