Ser Programador

Trabalhando com funções síncronas no jQuery utilizando Deferred

Vamos entender como executar funções após outra função finalizar a execução


Olá, pessoal!

Sabemos que o JavaScript executa tudo de forma assíncrona, dessa forma é necessário que pensemos com um pouco mais de cautela ao desenvolver aplicações em JavaScript/jQuery para que não criemos bugs, por vezes, difíceis de captar futuramente.

Mesmo tomando todos os cuidados ao construir nossos scripts, existem momentos em que precisamos executar alguma ação, mas dependemos que outra ação já tenha sido executada por completo.

Para resolver isto podemos utilizar o objeto Deferred do jQuery.

Consideremos que temos um cenário de um sistema que calcula juros incidente em um determinado valor.

Utilizarei a função setTimeout com timer de 3 segundos para simular a execução de um processamento. Portanto temos:

    	<script type="text/javascript">
        	function buscaValorBase(){
                setTimeout(function(){
                    return 1000;
                },3000);
            }
            
            function aplicaJuros(valorBase, jurosReajuste){
                return valorBase + (valorBase * (jurosReajuste/100));
            }
            
            $(document).ready(function(){
                var valorBase;
                var valorReajustado;
                var jurosReajuste = 15;//porcentagem de juros
                
                valorBase = buscaValorBase();
                valorReajustado = aplicaJuros(valorBase, jurosReajuste);
                
                alert(valorReajustado);
            });
		</script>
    

Para o cenário acima, o alert nos retornaria NaN porque ao executar a funcao aplicaJuros o valor que está na variável valorBase é undefined ao invés de 1000 como esperado. A causa disso é que no momento em que o JavaScript está executando este alert a função buscaValorBase chamada anteriormente ainda está executando, portanto ao efetuarmos cálculos com undefined o retorno será sempre Not a Number (NaN).


Vamos então introduzir na função buscaValorBase o objeto Deferred do jQuery:

    	<script type="text/javascript">
        	function buscaValorBase(){
            	var valor	= 1000;
				var df		= new $.Deferred();
                
                setTimeout(function(){
                    df.resolve(valor);
                },3000);
                
                return df.promise();
            }
    

Vejamos o que acontece:



Agora vamos ver como chamar a função buscaValorBase de uma forma que se comunique com o Deferred e nos retorne o valor correto:

    	<script type="text/javascript">
        	function buscaValorBase(){
            	var valor	= 1000;
				var df		= new $.Deferred();
                
                setTimeout(function(){
                    df.resolve(valor);
                },3000);
                
                return df.promise();
            }
            
            function aplicaJuros(valorBase, jurosReajuste){
                return valorBase + (valorBase * (jurosReajuste/100));
            }
            
            $(document).ready(function(){
                var valorBase;
                var valorReajustado;
                var jurosReajuste = 15;//porcentagem de juros
                
                $.when(buscaValorBase()).done(function(valorBase){
                    valorReajustado = aplicaJuros(valorBase, jurosReajuste);
                    alert(valorReajustado);
                });
            });
		</script>
    

Agora fizemos o seguinte:



Como de forma geral nem sempre os juros são fixos no mercado, o juros incidente para reajuste pode ser dinâmico. Neste caso, podemos trabalhar com mais de uma função simultânea para uma mesma chamada síncrona.

Vamos então criar uma função que efetue a busca do índice de juros:

    	<script type="text/javascript">
        	function buscaValorBase(){
            	var valor	= 1000;
				var df		= new $.Deferred();
                
                setTimeout(function(){
                    df.resolve(valor);
                },3000);
                
                return df.promise();
            }
            
            function buscaJuros(){
            	var valor	= 15;
				var df		= new $.Deferred();
                
                setTimeout(function(){
                    df.resolve(valor);
                },5000);
                
                return df.promise();
            }
            
            function aplicaJuros(valorBase, jurosReajuste){
                return valorBase + (valorBase * (jurosReajuste/100));
            }
            
            $(document).ready(function(){
                var valorBase;
                var valorReajustado;
                var jurosReajuste;
                
                $.when(buscaValorBase(), buscaJuros()).done(function(valorBase, jurosReajuste){
                    valorReajustado = aplicaJuros(valorBase, jurosReajuste);
                    alert(valorReajustado);
                });
            });
		</script>
    

Dessa forma temos:


Passando simultaneamente mais de uma função para o jQuery when, o callback no método done só será executado quando todas as funções passadas para o when finalizarem sua execução.



Perfeito! Agora seu código nunca mais terá problemas de assincronicidade!