Skip to content

Instantly share code, notes, and snippets.

@kaiquewdev
Last active January 2, 2016 00:09
Show Gist options
  • Save kaiquewdev/8221653 to your computer and use it in GitHub Desktop.
Save kaiquewdev/8221653 to your computer and use it in GitHub Desktop.
Callback hell? Let me show you a trick.
// Promessas podem resolver a sua vida.
// Mas se o Javascript foi pensado desta forma, com a possibilidade
// de funções dentro de funções, então existiria algum recurso para resolver este problema?
// Bom, não tem um recurso especifico que vai fazer a sua vida mudar, mas com algum conhecimento
// sobre a linguagem, você acaba descobrindo que isso pode acontecer.
// Primeiro exemplo - #1
function sayHello () {
var self = this;
console.log( self.message );
}
setTimeout( sayHello.bind({ message: 'Hello World!' }), 1000 );
// o que aconteceu?
// É bem simples, quando você define uma função que sera registrada e não executada
// Você pode costurar um novo contexto nela. Sendo assim, agora 'self.message' é igual ao valor 'message' que foi passado,
// dentro do objeto e costurado aquela função.
// Tá mas se eu estiver executando a minha função o '.bind' ira funcionar?
// Você pode tentar ver o que acontece, mas não tera sucesso.
// Então, como eu irei resolver isso?
// Segundo exemplo - #2
function sayHello () {
var self = this;
console.log( self.message );
}
function timeoutHandler () {
sayHello.call({ message: 'Hello World!' });
}
setTimeout( timeoutHandler, 1000 );
// Pronto, a mesma coisa aconteceu mas a unica diferença é que agora você esta costurando um novo contexto
// e chamando a função. Ela tera basicamente o mesmo comportamento. Mas e como eu posso resolver o meu problema?
// Como assim, problema? Você tem a solução na sua frente, primeiro que você deve considerar algumas regras antes.
// Tudo bem, promessas resolve o seu problema, mas é uma solução elegante e vale a pena?
// Terceiro exemplo - #3
var Post = require('post/model');
var content = {
title: 'Hello',
body: 'content of my post'
};
function successHandler () {
var self = this;
console.log( 'title: %s, body: %s', self.title, self.body );
}
function failHandler () {
var self = this;
console.log( 'error: %s', self.error );
}
function postSaveHandler ( err, result ) {
if ( !err && result ) {
successHandler.call( result );
} else {
failHandler.call( err );
}
}
Post( content ).save( postSaveHandler );
// Quarto exemplo - #4
// Um outro exemplo hipotético de como funcionaria, com um fluxo um pouco mais complexo.
// Aonde eu irei tratar as informações das "tags" dividindo elas por um padrão do tipo ", "
// e embutindo o conteudo do author nos dados do post.
// Pode não funcionar, para um caso real, mas é puramente para exemplificar um outro tipo de fluxo.
var Author = require('author/model');
var Post = require('post/model');
var content = {
title: 'Hello',
body: 'content of my post',
tags: 'tag1, tag2, tag3',
author: 'some-id' // fake information, starting from the principle of you was received an ObjectId
};
var authorQuery = { _id: content.author };
function successHandler () {
var self = this;
console.log( 'title: %s, body: %s', self.title, self.body );
}
function failHandler () {
var self = this;
console.log( 'error: %s', self.error );
}
function postSaveHandler ( err, result ) {
if ( !err && result ) {
successHandler.call( result );
} else {
failHandler.call( err );
}
}
function authorFindOneHandler ( err, result ) {
var self = content;
if ( !err && result ) {
// embed the content on the new post data.
self.author = result;
self.tags = self.tags.split(', ');
Post( self ).save( postSaveHandler );
} else {
failHandler.call( err );
}
}
Author
.findOne( authorQuery )
.lean( true ) // change the "result" to a literal object not an instance of Model of module mongoose
.exec( authorFindOneHandler );
// Bom, não precisamos de muito para resolver a questão dos callbacks ^ ^
// Agora é com você!
@kaiquewdev
Copy link
Author

Algumas regras que podem ser seguidas para manter a disciplina:

  • os nomes das funções são descritivos e seguem um padrão "entidade", "ação", "atuação";
    por exemplo: postSaveHandler -> função que lida com as regras para salvar o post.
    Utilizando a convenção do mongoose, que tem uma estrutura bem definida. E que tinha um enquadramento
    adequado para o que eu queria expressar.
  • uma função só pode ter um nivel de condicionais, clousures e outros blocos de código,
    se ela esta fazendo muitas coisas, tem algo de errado, então chegou a hora para separar
    em outras funções
  • O ideal e definir as funções lidando com uma responsabilidade,
    isso leva ao que acontece dentro do corpo da função "postSaveHandler" aonde ela
    resolve uma só responsabilidade e passa para uma outra função lidar com que for acontecer
    que neste caso é sucesso ou falha.

Que lhe da uma boa vantagem para trocar o contexto por exemplo no sucesso, de trocar por uma outra
função que leva para uma outra condição.

@kaiquewdev
Copy link
Author

Uma outra coisas que deve ser notada, é que definindo todas as variaveis no topo,
mesmo nulas, e manipulando posteriormente. O fluxo deve ser levado de baixo para cima,
e quando você estiver codificando, você ira de encontro com as variaveis definidas no topo,
que facilita uma consulta do que você esta manipulando.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment