Callback
Olha só que legal, callback é um termo bastante usado nas nossas aulas e deveremos entender a sua razão de existencia. O node.js trabalha fortemente com programação assíncrona, I/O assíncrono é só code-nome.
Vamos mostrar isso em código e explicar linha a linha.
/**
* Olha só
*/
function sayName (name, cb) {
if (typeof name === 'undefined') {
var error = new Error("Você deve passar um parâmetro como string para essa função, caraalho");
/*** aqui a gente só retorna o erro da nossa função */
return cb(err, null);
} else {
/*** agora definimos o nosso erro como null e retornamos o valor passado */
return cb(null, name);
}
}
A ideia de callback é justamente proporcionar uma extensão da continuação da função sayName, sem ter que precisar parar o código para fazer isso em uma outra função.
Para extendermos a execução de sayName, precisamos usar uma função anônima e passarmos como parâmetro, no segundo parâmetro.
/*** a função normal seria assim */
// sayName("Caio");
/*** função com callback */
sayName ("Caio", function (err, result) {
if (err) console.log(err);
console.log(result); // "Caio"
});
Confesso para os senhores que é um pouco verboso usar callback, mas só assim conseguimos garantir a continuação da execução de uma determinada função.
O legal é ter uma forma extendida de nossa função.
Esse estilo de programação é herdada do paradigma funcional que o javascript sofre influência, é facilmente confudível com o conceito de first-class function, porém o que se adequa mais ao conceito de continuação de uma função é o high-order-functions.
Essa continuação é um pattern de programação funcional chamado de continuation-passing-style. É bom conhecermos esses nomes por que se a gente quiser se aprofundar mais nos conceitos a gente sabe para onde ir :).
Nem tudo é mar de flores, nem tudo é tão bonito assim.
Callback-hell ou boomerang-effect:
E se agente quiser tratar callbacks como um certa ordem? Vejamos o seguinte exemplo com mais de uma função definida
function sayName (name, cb) {
// dessa vez a gente vai usar um primito assincrono
// para garantir que essa função seja assincrona de qualquer forma
setTimeout(function () {
if (typeof name === 'undefined') {
var error = new Error("Você deve passar um parâmetro como string para essa função, caraalho");
/*** aqui a gente só retorna o erro da nossa função */
return cb(err, null);
} else {
/*** agora definimos o nosso erro como null e retornamos o valor passado */
return cb(null, name);
}
}, 100);
}
function saySurname (name, cb) {
// dessa vez a gente vai usar um primito assincrono
// para garantir que essa função seja assincrona de qualquer forma
setTimeout(function () {
if (typeof name === 'undefined') {
var error = new Error("Você deve passar um parâmetro como string para essa função, caraalho");
/*** aqui a gente só retorna o erro da nossa função */
return cb(err, null);
} else {
/*** agora definimos o nosso erro como null e retornamos o valor passado */
return cb(null, name);
}
}, 105);
}
E agora para darmos uma ordem de execução desses callbacks:
sayName ("Caio", function (err, result) {
if (err) console.log(err);
console.log(result); // "Caio"
saySurname("Cutrim", function (err, result) {
if (err) console.log(err);
console.log(result); // "Cutrim"
});
});
Agora a gente tem uma pequena diferença quando colocamos um primitivo assíncrono chamado timer-function, isso deixa o nosso assíncrono, então se é assíncrono a gente não tem ordem na execução do nossos callbacks.
Você já consegue imaginar que se quisermos ter mais funções assíncronas a gente vai ter mais callbacks aninhados não é mesmo? ou seja:
sayName ("Caio", function (err, result) {
if (err) console.log(err);
console.log(result); // "Caio"
saySurname("Cutrim", function (err, result) {
if (err) console.log(err);
console.log(result); // "Cutrim"
sayFullName("Caio Cutrim", function (err, result) {
if (err) console.log(err);
console.log(result); // "Caio Cutrim"
});
});
});
Aff... a tendendência desse código é ficar cada vez mais feia devido a complexidade das funções que criarmos, então para evitar isso nós temos varias soluções que nós iremos tratar posteriormente. :)
Beijo no coração.