can-zone é uma biblioteca que implementa Zonas.
As zonas são uma abstração que permite escrever um código mais limpo para diversas finalidades, incluindo a implementação de aplicativos renderizados no lado do servidor (SSR), criação de perfis, rastreamentos de pilha mais úteis para depuração ou uma forma limpa de implementar a verificação de sujeira.
Este artigo irá:
- Explique o que são Zonas.
- Explique como funciona o can-zone.
- Mostrar a API básica do can-zone.
As zonas podem ser difíceis de entender no início, portanto, este artigo se limitará ao básico. Na próxima semana, publicarei um artigo de acompanhamento sobre blog.bitovi.com explicando como DoneJS usa can-zone para permitir que os aplicativos sejam renderizados no lado do servidor de forma elegante.
O que são Zonas?
Como o senhor já sabe, o JavaScript é uma linguagem assíncrona. O que isso significa na prática é que os mecanismos JavaScript contêm (várias) filas que são usadas para controlar as tarefas assíncronas a serem executadas posteriormente. Para pensar nisso, dê uma olhada em um exemplo simples de código assíncrono:
Esse código executa uma função, app
, que agenda a função logging
a ser chamada duas vezes com dois argumentos diferentes. Detalhando o que acontece no mecanismo JavaScript:
-
A tarefa de script é executada, o que define e executa o
app
A função setTimeout é chamada duas vezes, programando seus retornos de chamada para serem executados após 10 ms. -
Após 10 ms, a primeira tarefa será retirada da fila e executada até a conclusão, registrando de 0 a 500.
-
Após a conclusão da primeira tarefa, a segunda tarefa será retirada da fila e executada até a conclusão. Ela será registrada de 0 a 5000.
-
A fila de tarefas agora está vazia.
Para se aprofundar nas tarefas e microtarefas do JavaScript, consulte o artigo de Jake Archibald sobre o assunto.
As zonas oferecem uma maneira de se conectar ao comportamento do loop de eventos do JavaScript. Para visualizar melhor o que acontece no código acima, veja o que acontece quando o mesmo código é executado em uma zona usando can-zone.
Aqui temos o mesmo código, mas com a adição de registro antes e depois da execução de cada tarefa. Observe que as duas primeiras coisas que são registradas são “beforeTask” e “afterTask”. Isso ocorre porque a execução de app
é, por si só, uma tarefa. Então, quando as funções programadas pelo setTimeout são executadas, “beforeTask” e “afterTask” também são registrados para cada uma delas.
Com esse bloco de construção, podemos criar abstrações mais úteis para trabalhar com código que é executado em um loop de eventos. Uma que o can-zone oferece aos senhores é a capacidade de saber quando todas as tarefas assíncronas estão concluídas. Cada zona tem uma promessa associada que será resolvida quando todas as filas de tarefas forem esvaziadas.
No exemplo a seguir, temos um aplicativo que executa duas solicitações AJAX para exibir listas e, na parte superior, o tempo que levou para renderizar. Isso pode ser escrito usando Promessas, aguardando a resolução de todas as promessas, como abaixo:
Com apenas duas tarefas assíncronas para esperar, isso não é tão ruim, mas será mal dimensionado à medida que o código se tornar mais complexo (como se as solicitações fossem acionadas como um efeito colateral de alguma outra chamada de função):
Isso nos informa quanto tempo falta para as listas serem totalmente exibidas, mas podemos fazer melhor e saber quanto tempo levou para o nosso para que o código seja realmente executado, eliminando a latência da rede da equação. Usando os ganchos de zona discutidos anteriormente, beforeTask e afterTask, podemos medir apenas o tempo em que nosso JavaScript está sendo executado:
Essa técnica fornece informações sobre por que esse código leva tanto tempo para ser renderizado; não é culpa de um código mal escrito, mas sim da latência da rede. Com essas informações, podemos fazer otimizações mais informativas para o tempo de carregamento da página.
O conceito de Zonas está ganhando força no JavaScript. O Angular tem uma biblioteca Zone semelhante. Mas, enquanto a biblioteca do Angular zone.js tem como objetivo ajudar na depuração e melhorar o código de verificação de sujeira, enquanto o can-zone se concentra em resolver a renderização no lado do servidor.
Como funciona o can-zone
No futuro, os Zones poderão fazer parte do padrão EMCAScript, mas, por enquanto, o can-zone implementa o comportamento envolvendo funções que acionam eventos assíncronos (incluindo XHR, setTimeout, requestAnimationFrame). O can-zone não apenas envolve as funções, mas também mantém a contagem de quando as tarefas são concluídas e fornece uma API semelhante à Promise que permite saber quando todo o comportamento assíncrono foi concluído.
Acima, vimos alguns exemplos simples de Zones; abaixo está um exemplo mais complexo. Ele ilustra que, mesmo quando as chamadas assíncronas são aninhadas umas dentro das outras, o can-zone aguardará a conclusão de tudo.
Nos bastidores, o can-zone está substituindo os seguintes métodos:
- setTimeout
- clearTimeout
- XMLHttpRequest
- requestAnimationFrame
- Promessa
- process.nextTick (em Node)
- MutationObserver
Isso não altera seu comportamento principal. Ele simplesmente incrementa um contador para manter o controle de quantas callbacks restam. O contador é diminuído quando essas callbacks são chamadas. Quando a contagem chega a zero, a promessa da zona é resolvida.
API e recursos
Controle refinado sobre o código com o qual o senhor se preocupa
Zone.ignore
permitem que os usuários ignorem (não esperem) determinadas funções. O senhor pode usar isso se tiver um código fazendo setTimeouts recursivos (porque isso nunca será concluído) ou para alguma chamada de API que não seja importante o suficiente para esperar. Aqui está um exemplo de uso:
function recursive(){ setTimeout(function(){ recursive(); }, 20000); } var fn = Zone.ignore(recursive); // This call will not be waited on. fn();
Zone.waitFor
é uma forma de definir um comportamento assíncrono personalizado. O senhor pode pensar nisso como sendo o oposto de Zone.ignore
. Digamos que haja algumas tarefas assíncronas que o can-zone ainda não implementa, ou uma biblioteca do Node com ligações C++ personalizadas que fazem coisas assíncronas sem o nosso conhecimento. O senhor ainda pode envolver esses trechos de código para garantir que eles sejam aguardados:
var Zone = require("can-zone"); var fs = require("fs"); module.exports = function(filename) { fs.readFile(__dirname + filename, "utf8", Zone.waitFor(function(err, file){ Zone.current.data.file = file; })); };
Ganchos de ciclo de vida
O can-zone fornece ganchos para escrever código que é executado em vários pontos do ciclo de vida da zona:
- created – Chamado quando a zona é criada pela primeira vez.
- ended – Chamado quando a zona está prestes a ser resolvida.
- beforeTask – Chamado antes da execução de cada tarefa assíncrona.
- afterTask – Chamado após a execução de cada tarefa assíncrona.
- beforeRun – Chamado imediatamente antes da execução do
run
da Zona seja executada.
Esses ganchos são úteis na implementação de plug-ins. Anteriormente, criamos um plug-in de desempenho simples que usava beforeTask e afterTask para cronometrar o tempo que cada tarefa levava para ser executada.
Criar plug-ins
A função construtora do can-zone usa um objeto de configuração especial chamado ZoneSpec. O objeto ZoneSpec é onde o senhor:
- Crie retornos de chamada para os ganchos do ciclo de vida.
- Herdar comportamentos de outros plug-ins.
- Defina seus próprios ganchos para os quais outros plug-ins (que herdam do senhor) podem fornecer retornos de chamada.
- Defina os globais que devem ser substituídos nos retornos de chamada assíncronos da Zone.
Aqui está um exemplo de um plug-in que altera o título de sua página aleatoriamente.
var titleZone = { beforeTask: function(){ document.title = Math.random() + " huzzah!"; } }; var zone = new Zone({ plugins: [titleZone] });
O can-zone vem com alguns plug-ins que podem ser úteis para o senhor:
- can-zone/xhr: Pode ser usado no servidor e no cliente (supondo que o senhor tenha um shim XMLHttpRequest para o Node) para fornecer recursos de cache durante a renderização no lado do servidor.
- can-zone/timeout: Define um tempo limite, em milissegundos, no qual a promessa Zone será rejeitada.
- can-zone/debug: Usado em conjunto com can-zone/timeout, fornece rastreamentos de pilha de cada tarefa assíncrona que não foi concluída dentro do tempo limite.
Mais informações
- GitHub página do projeto
- Somente jQuery Exemplo de SSR can-zone com jQuery
- NPM página do projeto
- Instale-o:
npm install can-zone

Sobre Matthew Phillips
Matthew é um desenvolvedor de código aberto da Bitovi e um dos principais colaboradores do DoneJS. O foco de Matthew no DoneJS é o carregamento de módulos e a renderização no lado do servidor.