Created
August 15, 2014 10:47
-
-
Save chrisbuttery/9db089a90f20ccf855b4 to your computer and use it in GitHub Desktop.
Synchronous asynchronous JavaScript - Nicer callbacks
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
<html> | |
<head> | |
<style> | |
body { | |
background: #f5f8fa; | |
font: 16px/22px Arial, sans-serif; | |
margin: 0; | |
} | |
.statList { | |
background: #fff; | |
border-bottom: 1px solid #e1e8ed; | |
height: 60px; | |
overflow: hidden; | |
} | |
.statList__item { | |
float: left; | |
width: 75px; | |
height: 60px; | |
display: table; | |
} | |
.status { | |
display: table-cell; | |
text-align: center; | |
text-transform: uppercase; | |
vertical-align: middle; | |
} | |
.title { | |
color: #66757f; | |
font-size: 11px; | |
letter-spacing: .02em; | |
text-transform: uppercase; | |
} | |
.count { | |
color: #C29A34; | |
font-size: 18px; | |
font-weight: 500; | |
padding-top: 3px; | |
} | |
.tweetFeed { | |
margin: 10px; | |
} | |
.tweet { | |
background: #fff; | |
border: 1px solid #e1e8ed; | |
padding: 15px; | |
} | |
.tweet:nth-child(1){ | |
border-radius: 5px 5px 0 0; | |
} | |
.tweet:nth-child(n+2){ | |
border-top: none; | |
} | |
.tweet__name{ | |
color: #292f33; | |
display: inline-block; | |
font-size: 14px; | |
font-weight: bold; | |
} | |
.tweet__handle { | |
color: #8899a6; | |
display: inline-block; | |
font-size: 13px; | |
margin-left: 10px; | |
} | |
.tweet__message { | |
margin-top: 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="statList"> | |
<div class="statList__item"> | |
<div class="status"> | |
<div class="title">Tweets</div> | |
<div class="count totalTweets"></div> | |
</div> | |
</div> | |
<div class="statList__item"> | |
<div class="status"> | |
<div class="title">Photos</div> | |
<div class="count totalPhotos"></div> | |
</div> | |
</div> | |
<div class="statList__item"> | |
<div class="status"> | |
<div class="title">Favourites</div> | |
<div class="count totalFavourites"></div> | |
</div> | |
</div> | |
</div> | |
<div class="tweetFeed"> | |
<div class="timeLine"></div> | |
</div> | |
<script type="text/javascript"> | |
var timeLine = document.querySelector('.timeLine'); | |
var totalTweets = []; | |
/** | |
* get | |
* | |
* Tiny utility for making XHR requests | |
* @param {String} url | |
* @param {Function} callback [description] | |
*/ | |
function get(url, callback, errback) { | |
var req = new XMLHttpRequest(); | |
req.open('GET', url, true); | |
req.onreadystatechange = function() { | |
if(req.readyState != 4) return; | |
if (req.status === 200) { | |
callback(req); | |
} | |
else { | |
errback(req); | |
} | |
}; | |
req.send(null); | |
} | |
/** | |
* Asynch Requests | |
*/ | |
// our first async req | |
function get1stTweet(){ | |
get('https://api.myjson.com/bins/2qjdn', | |
function(data){ | |
totalTweets.push(data.response); | |
next(); | |
}, | |
function(err){ | |
onError(err); | |
} | |
); | |
} | |
// our second async req wrapped in a 2 second delay | |
function get2ndTweet(){ | |
setTimeout(function(){ | |
get('https://api.myjson.com/bins/3zjqz', | |
function(data){ | |
totalTweets.push(data.response); | |
next(); | |
}, | |
function(err){ | |
onError(err); | |
} | |
); | |
}, 2000); | |
} | |
// our third async req | |
function get3rdTweet(){ | |
get('https://api.myjson.com/bins/29e3f', | |
function(data){ | |
totalTweets.push(data.response); | |
next(); | |
}, | |
function(err){ | |
onError(err); | |
} | |
); | |
} | |
/** | |
* showStats | |
* | |
* Populate some stats | |
*/ | |
function showStats(){ | |
var totalTweets = document.querySelector('.totalTweets'); | |
totalTweets.textContent = countProperties('user') || 0; | |
var totalPhotos = document.querySelector('.totalPhotos'); | |
totalPhotos.textContent = countProperties('photo') || 0; | |
var totalFavourites = document.querySelector('.totalFavourites'); | |
totalFavourites.textContent = countProperties('favourited') || 0; | |
next(); | |
} | |
/** | |
* showTimeline | |
* | |
* Flesh out some sweet sweet tweet data | |
* then append to the .timeLine | |
*/ | |
function showTimeline(){ | |
var el = document.createElement('div'); | |
totalTweets.forEach(function(tweet){ | |
tweet = JSON.parse(tweet); | |
var tweetElement = el.cloneNode(true); | |
tweetElement.classList.add('tweet'); | |
var name = el.cloneNode(true); | |
name.classList.add('tweet__name'); | |
name.textContent = tweet.user.name; | |
var handle = el.cloneNode(true); | |
handle.classList.add('tweet__handle'); | |
handle.textContent = '@' + tweet.user.handle; | |
var message = el.cloneNode(true); | |
message.classList.add('tweet__message'); | |
message.textContent = tweet.message; | |
tweetElement.appendChild(name); | |
tweetElement.appendChild(handle); | |
tweetElement.appendChild(message); | |
timeLine.appendChild(tweetElement); | |
}); | |
} | |
/** | |
* OnError | |
* | |
* @param {error} err | |
*/ | |
function onError (err) { | |
console.error("Error: err"); | |
} | |
/** | |
* countProperties | |
* | |
* Utility function to help us count certain props | |
* | |
* @param {String} a specific prop | |
* @return {Number} count | |
*/ | |
function countProperties(prop) { | |
var count = 0; | |
totalTweets.forEach(function(tweet){ | |
tweet = JSON.parse(tweet) | |
if (prop in tweet) count++; | |
}); | |
return count; | |
} | |
// Define a queue of functions | |
var fns = [get1stTweet, get2ndTweet, get3rdTweet, showStats, showTimeline]; | |
/** | |
* [next description] | |
* @param {[type]} val [description] | |
* @return {Function} [description] | |
*/ | |
function next(){ | |
var fn = fns.shift(); | |
if (fn != null) { | |
fn(); | |
} | |
else { | |
// just in case a method calls next() and there | |
// are more functions in `fns` to call | |
return; | |
} | |
} | |
// lets kick it off! | |
next(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
All the getTweet's functions can be simplified a bit by using the fact that you can use functions as values.
You allready defined
onError
, so there is no reasion to wrap it in another function for theget
call.The
success
function is identical for all the functions so it should be extracted and passed as a value aswell.You could even mage
get
a higher-order function so you could write.Added the small change to the original code and tested that it works.