AngularJS: Diferenças entre $apply, $timeout, $evalAsync e $digest

Fala galera, beleza?

Após alguns meses sem nenhuma novidade por aqui, estou tentando retornar a rotina de publicações… A ausência foi por um bom motivo: estive desenvolvendo, e ainda estou, um projeto social chamado Doe Caridade. Mas em breve eu volto a falar sobre ele, pois pretendo abrir o código fonte.

O post de hoje é sobre as diferenças entre o $apply, $timeout, $evalasync e $digest. Para entendermos um pouco mais como o AngularJS funciona é importante conhecê-las e saber como e quando usá-las.

$apply()

Algumas vezes é necessário executar operações fora do escopo do AngularJS. No post sobre Socket.io e AngularJS: Comunicação em tempo real, por exemplo, falei sobre a execução do $apply para poder atualizar o escopo do AngularJS todas as vezes que o frontend recebia dados do backend através do socket.io.

Para que essas operações realizadas fora do escopo tenham efeito é preciso fazer com que o escopo do AngularJS seja atualizado. Então, uma das funções que executa esse papel é a $apply.

Ela é a responsável por executar todos os observadores do escopo da aplicação. Isso quer dizer que cada vez que a função for chamada, todo o ciclo de vida da aplicação será atualizado.

Muito cuidado, no entanto, com o excesso de utilização do $apply, pois ele é um processo pesado e pode levar a problemas de desempenho da aplicação.

Outro ponto a ser mencionado é que o AngularJS possui um único ciclo. Isso quer dizer que essa função não pode ser invocada enquanto houver um ciclo em progresso. Caso isso ocorra, o seguinte erro será lançado $digest already in progress (para saber mais acesse esse link). 

$timeout()

O $timeout é uma maneira mais fácil de resolver operações que são executadas fora do escopo do AngularJS. No post sobre AngularJS: Aplicação em tempo real – Refresh periódico falei um pouco sobre ele, vale a pena conferir.

Uma grande vantagem dessa função é que não receberemos a exceção de que o ciclo do AngularJS está em progresso. Por baixo dos panos, o $timeout informa ao framework que ao terminar o ciclo atual há um timeout esperando para ser executado. Assim, não haverá conflito entre o ciclo atual e a execução do timeout.

$evalAsync()

Essa função é uma espécie de irmão mais esperto do $timeout. A diferença básica entre elas é que o $evalAsync pode ser avaliado na execução do escopo atual ou no próximo ciclo do AngularJS. Aqui tem um post bacana do Ben Nadel falando sobre $evalAsync e $timeout.

$digest()

É através da $digest() que o AngularJS percebe as mudanças entre o model e a view. Em cada ciclo $digest os observadores são executados.

Ao contrário da função $apply, que executa $digest a partir do $rootScope para os seus filhos, a função $digest() inicia o ciclo $digest dentro do escopo em que ele foi executado até seus filhos. Essa grande diferença pode reduzir a quantidade de observadores implementados pela aplicação.

Porém, apesar do ganho de performance com o uso dessa função, o desenvolvedor deve ficar atento se o escopo pai utiliza as novas informações, pois ele não é atualizado e as expressões podem ficar defasadas.

Entender como é o funcionamento do ciclo do AngularJS é importante para saber tratar problemas de performance. Neste post mostrei opções que se aplicadas corretamente podem melhorar o desempenho da sua aplicação.

Por hoje é só galera.

Abraços e até a próxima!