Reputation: 193
I am trying to wrap my head around callbacks and events. There are two common patterns associated with each. Which one is considered best practice, and why?
I have a callback-oriented piece of code as follows:
$(function() {
console.log('Document ready');
getData();
})
function getData(){
var url = "http://ip.jsontest.com/";
$.ajax({
dataType: "json",
url: url,
success: function(data){
buildElements(data, writeData)
}
});
}
function buildElements(data, callback) {
$('div.foo').append("<div class='bar'></div>");
callback(data);
}
function writeData(data){
$('div.bar').append('<p>Your IP is ' + data.ip + '</p>');
}
And then an event-oriented piece of code (following the observer pattern) as follows:
$(function() {
console.log('Document ready');
getData();
})
function getData(){
var url = "http://ip.jsontest.com/";
$.ajax({
dataType: "json",
url: url,
success: function(data){
$('div.foo').trigger('getDataDone', data);
}
});
}
//build elements
$('div.foo').on('getDataDone', function(event, data) {
$('div.foo').append("<div class='bar'></div>")
$('div.foo').trigger('elementsBuilt', data);
})
//write data
$('div.foo').on('elementsBuilt', function(event, data) {
$('div.bar').append('<p>Your IP is ' + data.ip + '</p>');
})
Upvotes: 2
Views: 209
Reputation: 2540
The somewhat procedural nature of the callback pattern allows you to more strictly define your program flow. The logic will be:
and so on. This works brilliantly for ajax calls because that path of execution is easy to maintain.
The observer pattern makes it possible to allow multiple listeners to act on the event (they are observing for a change). So it looks like:
So in your observer example, you can easily have many more .on('elementsBuilt') and do a whole host of other things, relatively simultaneously. Great for observers coming alive and dying at totally arbitrary times.
In terms of best practice, it depends on what you are trying to achieve. If you require a more defined solution where you typically want to follow on one action at a time, go the callback pattern route. If you need multiple things to happen in different places and you especially are not concerned about the order of who handles the event first, go the observer pattern route.
Upvotes: 1
Reputation: 17817
Event-oriented provides more loose coupling so it has benefits, but at the same time it makes harder to track which parts of the your system communicate so you might wan't to develop some tools for your project to log and inspect which components of your systems emit events and which react to events.
You might want to keep some discipline about which components can attach event handlers. I've seen that it's a good idea to not attach events in leaf components and do that in their parents that calls appropriate children's methods in response to an event.
You might wan't to look at promises. It's more loose than callbacks but at the same time they are passed around your code explicitly so it's easier to track what happens just by looking at the source code.
Example with promises:
$(function() {
console.log('Document ready');
gettingData()
.done(function(data) {
buildingElements(data)
.done(writeData);
});
//// alternatively:
//gettingData()
//.then(buildingElements)
//.done(writeData);
})
function gettingData(){
var url = "http://ip.jsontest.com/";
// $.ajax returns a promise
return $.ajax({
dataType: "json",
url: url
});
}
function buildingElements(data) {
$('div.foo').append("<div class='bar'></div>");
// returns immediately resolved promise, but it could return a promise but resolve it asynchronously later
return $.Deferred().resolve(data).promise();
}
function writeData(data){
$('div.bar').append('<p>Your IP is ' + data.ip + '</p>');
}
Upvotes: 1