-
-
Save matthamil/c404a3e1796a1257fcd0 to your computer and use it in GitHub Desktop.
A conjurer's guide to promises
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 quick example of how to use Bluebird and Q to conjure your own promises | |
* | |
* Everything going on here is explained further in the following video: | |
* http://youtu.be/OU7WuVGSuZw?list=PLT-DLWOBKbB4dZ83I_7Ca-sUTvorckG-E | |
* | |
*/ | |
// Import node modules | |
var Q = require('q'); | |
var Promise = require('bluebird'); | |
var GitHubApi = require('github'); | |
// Instantiate GitHub API. | |
// NOTE: GitHub is just used for async demonstration purposes, you can imagine any other async functions throughout this example | |
var github = new GitHubApi({ | |
version: '3.0.0' | |
}); | |
/* * * * * A typical callback pattern * * * * * * */ | |
var getUserAvatarWithCallback = function(user, callback) { | |
// Use our node-github library to search for a specific user. This is async so we have to pass it a callback. | |
github.search.users({ q: user }, function(error, response) { | |
// Couldn't find a user for some reason. Pass along the error with the regular node pattern (error, response) | |
if (error) { callback(error, null); } | |
else { | |
var avatarUrl = response.items[0].avatar_url; // We know the specific property of interest from the github API docs | |
callback(null, avatarUrl); // Pass along our avatarUrl with the regular node pattern (error, response) | |
} | |
}); | |
}; | |
// Invoke our function, passing it a callback that will accept the avatar url as it's only parameter | |
getUserAvatarWithCallback('danthareja', function(error, url) { | |
console.log('Got url with callback pattern', url); | |
}); | |
/* * * * * Promises * * * * * * */ | |
// ------- Bluebird ----------- | |
var getUserAvatarWithBluebird = function(user) { | |
// Create and return a promise object using the 'new' keyword -> this is special to Bluebird's implementation | |
// Promises will be native in ES6 and will use the same syntax as Bluebird | |
return new Promise(function(resolve, reject) { | |
github.search.users({ q: user }, function(error, response) { | |
// Whatever is passed into reject gets can be accessed in the 'catch' block's callback function | |
if (error) { reject(error); } | |
else { | |
var avatarUrl = response.items[0].avatar_url; | |
// Pass arguments of interest into resolve | |
// Whatever is passed into resolve gets can be accessed in the 'then' block's callback function | |
resolve(avatarUrl); | |
} | |
}); | |
}); | |
}; | |
// Invoke our 'promisified' function | |
getUserAvatarWithBluebird('danthareja') | |
.then(function(url) { | |
console.log('Got url with Bluebird promises', url); | |
}) | |
.catch(function(error) { | |
console.log('Error getting avatar with q', error); | |
}); | |
// ------------ Q ------------- | |
var getUserAvatarWithQ = function(user) { | |
// Create a deferred object using Q's 'defer' constructor -> this is special to Q's implementation | |
var deferred = Q.defer(); | |
github.search.users({ q: user }, function(error, response) { | |
if (error) { deferred.reject(error); } // deferred.reject syntax is special to Q | |
else { | |
var avatarUrl = response.items[0].avatar_url; | |
deferred.resolve(avatarUrl); // deferred.resolve syntax is special to Q | |
} | |
}); | |
// The promise we want to return exists on Q's deferred object | |
return deferred.promise; | |
}; | |
// Invoke our 'promisified' function | |
// Even though we use different syntax to create promises with bluebird and Q, the returned promise works exactly the same way | |
// i.e. they all have .then(), .catch(), .finally() | |
getUserAvatarWithQ('danthareja') | |
.then(function(url) { | |
console.log('Got url with q promises', url); | |
// Then's are chainable! Whatever we return in the previous 'then' gets passed into the next one | |
return url + ' SUPERAWESOMEAPPENDEDTEXT!!!!!! WOO!'; | |
}) | |
.then(function(appendedAvatarURL) { | |
console.log('Check out the new appended url', appendedAvatarURL); | |
// We can return promises in the chain too! | |
// Our next then function will only run after the promise is resolved. | |
// Herein lies the true power of promsies, play around with this to learn more! | |
var deferred = Q.defer(); | |
// use setTimeout to simulate an aync process before the resolve. Anything asyncronous could happen here | |
setTimeout(function() { | |
deferred.resolve(appendedAvatarURL + ' and we did more async!'); | |
}, 1000); | |
return deferred.promise; | |
}) | |
.then(function(appendedAvatarURLAfterAnotherAsyncOperation) { | |
// This 'then' function will only execute after the promise returned from the previous function has been resolved | |
console.log('Now check out the even moar appended url! Woah!', appendedAvatarURLAfterAnotherAsyncOperation); | |
}) | |
.catch(function(error) { | |
// Any error caught in a 'then' function above will break the chain and immediately run this function | |
console.log('Error somewhere in the getUserAvatarWithQ chain', error); | |
}) | |
.finally(function() { | |
// the 'finally' function will always get run regardless if the promise was resolved (successful) or rejected (errored) | |
console.log('This will always get run'); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment