What is Callback Inferno
Using your own code as an example. We can see that callback hell is defined by this pyramid at the end of })
. Simply awful.
Here's the snippet:
})
}.bind(this))
}
})
})
}
})
How can I avoid it?
The only way to avoid the hell of callbacks is to keep good practice on your codes. Being these practices
1. Keep Code Clean and Easy
This is an example of a code that is clearly bad.
var form = document.querySelector('form')
form.onsubmit = function (submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, function (err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
Let's name the functions
var form = document.querySelector('form')
form.onsubmit = function formSubmit (submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, function postResponse (err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
Naming roles has immediate benefits like:
- Make the code easy to read thanks to a description of the function in their names,
above we have postResponse and formSubmit, which are self-explanatory.
- When exceptions occur you will get more informative traces of
where the problem lies directly in functions rather than strangers
"anonymous".
- Allows you to reference their functions.
Finally you can move the functions to the top of the program and you will hardly have problems with the hell of the callbacks.
document.querySelector('form').onsubmit = formSubmit
function formSubmit (submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse (err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
2. Modularize
Anyone who does a correct code modularization will hardly have a problem with the hell of callbacks
.
Creating a file named formuploader.js
that contains our previous functions
, we can use module.exports
to modularize everything:
module.exports.submit = formSubmit
function formSubmit (submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse (err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
In Node.js we have the famous require, however we can also use this require in our browser with browserify . So we have access to require, so we can call the module we created in the file formuploader.js
and then using the created module.
var formUploader = require('formuploader')
document.querySelector('form').onsubmit = formUploader.submit
And now we have two vital advantages. Two of them are:
- Easy to read by new developers
- formuploader can be used elsewhere.
3. Avoid errors
Surely mistakes can happen, you need to take care that they do not go through the code without you knowing where they are. Many callbacks are built with an argument that helps us deal with these errors.
For example:
var fs = require('fs')
fs.readFile('/Does/not/exist', handleFile)
function handleFile (error, file) {
if (error) return console.error('Uhoh, there was an error', error)
// otherwise, continue on and use 'file' in your code
}
Notice the error argument being treated in return console.error('Uhoh, there was an error', error)
extremely important in case of a problem.
More About Callbacks Hells or Hell