Sexy.js is a lightweight JavaScript library which provides a sleek facade and enhanced Sequential Ajax (Sajax) functionality to jQuery’s native Ajax methods.
Sequential Ajax, or Sajax, is an Ajax design pattern where related asynchronous XMLHttpRequests are made simultaneously and their callbacks fired in a specified sequence, regardless of the order in which they return, with each callback function receiving the return value of the previous callback function as an additional argument.
The Sajax pattern simplifies and speeds the loading of scripts, stylesheets, and data, while facilitating the combination and manipulation of data from multiple sources without complicated workarounds to handle the implicit timing issues of Ajax’s asynchronous nature.
And Sexy.js makes it look good.
Damn good.
<script src="/js/jquery.template.min.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" href="css/comments.css" type="text/css" media="screen" charset="utf-8"/>
<script type="text/javascript" charset="utf-8">
$.get('comments.tpl', function (tpl) {
$.getJSON('comments.json', function (data) {
$.template(tpl, data).appendTo('#comments');
});
});
</script>
<script type="text/javascript" charset="utf-8">
Sexy
.js('/js/jquery.template.min.js')
.css('css/comments.css')
.text('comments.tpl')
.json('comments.json', function (data, status, tpl) {
$.template(tpl, data).appendTo('#comments');
});
</script>
Sexy provides a chainable API for loading each of the data types supported by jQuery’s native Ajax methods:
- html (url, callback)
- json (url, callback)
- jsonp (url, callback)
- script (url, callback)
- text (url, callback)
- xml (url, callback)
as well as one additional method for loading CSS (local file access only):
- style (url, callback)
and two aliases for sex appeal:
- js (url, callback) // → script
- css (url, callback) // → style
Each of the above methods can take either a url and optional callback as argument or a single ajaxSetup config object (see jQuery documentation).
All callbacks receive three arguments: data and status (from jQuery’s native functionality) and previous which is the return value of the previously executed callback.
If no callback is supplied for any of the data carrying calls (html, json, jsonp, text, xml), a pass-through function automagically returns the request data to the next callback.
Sexy
.js('/js/jquery.template.min.js')
.css('css/comments.css')
// Note there is no callback...
.text('comments.tpl')
// ...yet the tpl appears over here!
.json('comments.json', function (data, status, tpl) {
$.template(tpl, data).appendTo('#comments');
});
If no callback is supplied for the two non-data carrying calls (script/js, style/css) or setup, a pass-through function automagically returns the most recently returned value.
Sexy
// Note there is no callback...
.text('comments.tpl')
// ...none here either...
.js('/js/jquery.template.min.js')
// ...or here...
.css('css/comments.css')
// ...yet the tpl appears over here!
.json('comments.json', function (data, status, tpl) {
$.template(tpl, data).appendTo('#comments');
});
You can also set a default configuration for successive calls:
- setup (cfg)
setup can be used anywhere in the chain to change the default configuration. Passing no arguments will remove any previously configured options.
Sexy also has an additional method for bundling packaged scripts:
- bundle (url , url2, …, callback)
The bundle method loads multiple scripts as text and, once all requests are complete, makes a single script injection, and then fires the optional callback. This method is useful for maintaining JavaScript in packages in an environment that doesn’t support or necessitate a server-side bundling solution.
Binding
Sexy
.json('ticketingData.json', function (data) {
return data.ticketingInfo;
})
.json('gameData.json', function (data, status, ticketingInfo) {
for (var i = 0, n = data.games.length; i < n; ++i) {
data.games[i].ticketingInfo = ticketingInfo[data.games[i].id];
}
// render games...
});
Sexy
.json('ticketingData.json', function (data) {
return data.ticketingInfo;
})
.json('gameData.json', function (data, status, ticketingInfo) {
for (var i = 0, n = data.games.length; i < n; ++i) {
data.games[i].ticketingInfo = ticketingInfo[data.games[i].id];
}
// render games...
});
Bootstrapping
Sexy
.js('js/jquery.template.min.js')
.css('css/comments.css')
.text('comments.tpl', function (data, status, previous) {
return data;
})
.json({
url: 'comments.json',
data: { articleId: 123 },
success: function (data, status, previous) {
$.template(previous, data).appendTo('#comments');
}
});
Sexy
.js('js/jquery.template.min.js')
.css('css/comments.css')
.text('comments.tpl', function (data, status, previous) {
return data;
})
.json({
url: 'comments.json',
data: { articleId: 123 },
success: function (data, status, previous) {
$.template(previous, data).appendTo('#comments');
}
});
Bundling
Sexy
.bundle(
'mlb.js',
'mlb.stats.js',
'mlb.stats.widget.js',
'mlb.stats.widget.LeagueSelector.js',
'mlb.stats.widget.StatTypeSelector.js',
'mlb.stats.app.js',
'mlb.stats.app.SortableStats.js',
function () {
mlb.stats.app.SortableStats.init();
}
);
Sexy
.bundle(
'mlb.js',
'mlb.stats.js',
'mlb.stats.widget.js',
'mlb.stats.widget.LeagueSelector.js',
'mlb.stats.widget.StatTypeSelector.js',
'mlb.stats.app.js',
'mlb.stats.app.SortableStats.js',
function () {
mlb.stats.app.SortableStats.init();
}
);
The original goal when designing
NOTE: The library is just entering beta, but is currently in use on MLB.com’s 2010 website (in development). Stay tuned for more…