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:



Exemplo de 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:


  1. 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.

  2. Após 10 ms, a primeira tarefa será retirada da fila e executada até a conclusão, registrando de 0 a 500.

  3. 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.

  4. 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.



Zona beforeTask e afterTask

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:



Estruturas

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):



Estruturas II

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:



Carregamento mais rápido

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.



zona can

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

Matthew Phillips

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.