Javascript - entendendo e criando suas próprias Promises

Você já deve ter ouvido falar sobre Promises, e provavelmente sabe do problema que elas resolvem. Mas você sabe como implementar suas próprias Promises? Vamos ver como fazer isso na prática!

O problema - callback hell

Sempre que você precisa executar uma ação após uma requisição assíncrona, normalmente o código vai se parecer com isso:

1
2
3
4
5
6
7
8
9
obj.asyncFunction(function( response ) {
response.asyncFunction(function( response2 ) {
response2.asyncFunction(function( response3 ) {
response3.asyncFunction(function(response4 ) {
return response4;
});
});
});
});

Esse é o famoso callback hell, onde você depende do retorno de cada requisição para iniciar a próxima! Parece que o Ryu está dando uma hadouken ali!

Como resolver?

Solução 1: Métodos acoplados

Você pode resolver o callback hell usando métodos acoplados, ou seja, um método que vai depender de outro como resposta:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
obj.asyncFunction( responseFunc );

function responseFunc( response ) {
response.asyncFunction( responseFunc2 );
}

function responseFunc2( response2 ) {
response2.asyncFunction( responseFunc3 );
}

function responseFunc3( response3 ) {
response3.asyncFunction( responseFunc4 );
}

function responseFunc4( response4 ) {
return response4;
}

Isso já ajuda a resolver o problema do callback hell. Mas tem uma forma ainda mais elegante: Promises!

Solução 2: Promises

As Promises, como o próprio nome diz, são promessas de que você terá um resultado ao final da requisição. Um exemplo é o método $.get do jQuery. Você passa a URL onde você vai buscar seus dados para esse método, e, ao finalizar, você pode utilizar os métodos done(), para saber se o retorno foi bem sucedido, fail() para erro e always() para o final da requisição, independente de sucesso ou erro.

Dessa forma, você consegue utilizar algo como:

1
2
3
4
5
6
7
8
9
10
$.get( 'http://myapp.com/api/data' )
.done(function( data ) {
// => retorno com sucesso!
})
.fail(function() {
// => retorno com erro!
})
.always(function() {
// => final da requisição!
});

Assim você remove o acoplamento de várias funções, e usa métodos encadeados. :)

Essa é a ideia inicial da utilização de Promises. Nos próximos artigos, vamos construir um módulo que faz requisições Ajax, parecido com esse do jQuery, mas implementando nossas próprias Promises de success e error para os verbos get, post, put e delete. Esse nosso módulo será todo coberto por testes, então se prepare para uma grande aventura :D

Até lá!

Próximos artigos dessa série:

Sobre o #1postperday: https://blog.da2k.com.br/2014/12/31/um-post-por-dia/

Tem alguma sugestão para os próximos posts do #1postperday? Deixe ela aqui: https://github.com/fdaciuk/fdaciuk.github.io/issues/1