Skip to content

Instantly share code, notes, and snippets.

@peta
Created March 14, 2018 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peta/c4f80ab081db6ef21707277674f93d44 to your computer and use it in GitHub Desktop.
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
// 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';
});
});
// 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);
});
// 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