Arquivos da categoria: Javascript

WebWorkers

HTML5_Logo_512A execução de código Javascript é feita somente usando uma thread pelo navegador cliente. O navegador nunca vai executar dois eventos ao mesmo tempo. Funcões Javascript que tem execução mais longa travam a interface com o usuário até que termine sua execução.

As aplicações Web podem rodar melhor se as partes do código Javascript que exigem maior processamento fossem separadas em mais threads.

Execute dentro de uma página o código Javascript abaixo que simula um processamento demorado e tente usar a interface da página. Tudo estará travado, até que a execução do código termine.


function execucaoDemorada(){

    var tempoDeEspera = 10000; //10 segundos
    var inicio = (new Date()).getTime();
    var i = 0;
    while(((new Date()).getTime() - inicio) <= tempoDeEspera){
        console.log(i);
        i++;
    }
}

Em HTML5 é possível usar Web Workers, que dá poder ao Javascript em executar thread paralelas sem bloquear/travar a interface com o usuário.

Um WebWorker não deve ser usado para operações triviais, e sim para operações complexas e longas:

  • Codificação/decodificação de uma sequência grande;
  • Cálculos matemáticos complexos (por exemplo, números primos, criptografia, simulados, algoritmos de reconhecimentos, etc);
  • Classificando uma grande variedade de dados;
  • Solicitações de rede e processamento de dados;
  • Cálculos e manipulação de dados sobre o local/sessionStorage;
  • Algoritmo de verificação/checagem de sintaxe ou análise outro texto em tempo real (por exemplo, a verificação ortográfica);
  • Manipulação de Imagem;
  • Analisar ou processar vídeo ou dados de áudio (incluindo face e reconhecimento de voz);
  • Processamento de matrizes de grandes dimensões ou respostas JSON enormes;

Um worker nada mais é que um script que irá ser carregado e executado em segundo plano, por exemplo:


var wk1 = new Worker("worker1.js");

A função construtura Worker() recebe por parâmetro uma URL especificando o arquivo contendo o código Javascript que será tratado em um nova thread,

O código javascript contido no arquivo carregado pelo worker não tem acesso ao objeto Window, Document e a árvore DOM da página que iniciou sua execução.

A comunicação entre o worker e a página ocorre através de mensagens. Objeto gerado pela classe Work oferece o método postMessage(). É ele que vai enviar solicitações da página para o código dentro do workers.  Além de enviar string, oferece envio de mensagens no no formato JSON. E as mensagens de retorno podem ser capturada associando uma função ao evento  do objeto worker criado.


//Código na página.

var wk1 = new Worker("worker1.js"); //Criando o worker

//Monitorando as mensagens de retorno.
wk1.onmessage = function (e) {
    if (e.data.acao == "mostrar")
        document.getElementById("incrementos").innerHTML = e.data.incremento;
    else if (e.data.acao == "parar")
        wk1.terminate();
};

//É aqui que começa a execução do worker
wk1.postMessage("executar");

O evento onmessage fica monitorando as mensagens vindas worker para página. A função que vai tratar o evento recebe um parâmetro que possui uma propriedade data que contem a mensagem enviada pelo worker. No exemplo acima, o retorno a mensagem de retorno do worker é um objeto JSON.

O código contido no arquivo (do worker) também tem um evento onmessage e deve ter uma função associada, mas aqui é o worker que vai ficar escutando a página. Quando o método postMessage() na página é usado, é a função onmessage do worker que captura a mensagem que também é acessada pela propriedade data do parâmetro da função.

Para o worker enviar uma mensagem para a página, é também através do método postMessage().


//Código do worker.

// Evento que monita mensagens vindas da página para o worker
onmessage = function (e) {

    //e.data contém o valor enviado pela página.
    if (e.data === "executar") {

        execucaoDemorada();

        postMessage("fim");
    }
};

function execucaoDemorada(){

    var tempoDeEspera = 10000; //10 segundos
    var inicio = (new Date()).getTime();
    var i = 0;
    while(((new Date()).getTime() - inicio) <= tempoDeEspera){
        postMessage({ "acao": "mostrar", "incremento": i }); //envia uma nova mensagem para a página
        i++;
    }
    postMessage({ "acao": "parar"}); //envia uma nova mensagem para a página
}

Uma boa prática é fazer a liberação da thread na página pelo método terminate() do próprio objeto worker.

Outra informação importante é a possibilidade de ter páginas auto-suficiente, ou seja, o código a ser executado numa nova thread pode estar nela mesmo, sem a necessidade de separar num novo arquivo Javascript.

Até mais e baixe o exemplo aqui.

Introdução ao JSON – Javascript Object Notation

json160JSON é um formato para troca de dados baseado em estruturas de texto, o que lhe dá a característica de ser completamente independente de linguagem. É a mesma ideia do XML, só que mais simples e leve.

No site oficial (http://www.json.org/) o autor ainda afirma:

Para seres humanos, é fácil de ler e escrever.
Para máquinas, é fácil de interpretar e gerar.

A forma simples de representar dados no formato JSON tem difundido seu uso, e vem se tornando uma alternativa ao XML para implementações AJAX.

Em JSON podemos estruturar dados em (1) coleções de pares de nome e valor e também em (2) lista/array ordenadas de valores.

Os valores dos dados são representando em três formas: object, value e array, e ainda podem ser combinadas.

Object: é um conjunto de pares de nome/valores. A sintaxe de um object é


{ "nome da propriedade" : "valor da propriedade" }

O object começa com { e termina com }. E cada par de nome/valores é separado por ,(vírgula), sendo que os valores podem assumir diferente tipos de dados. Exemplo:


{“nome” : “Bill”, “idade” : 32, “salario”: 121232.67}

Array: é uma coleção de valores ordenados. A sintaxe de um array JSON é:


[ "valor1",  "valor2", "valor3" ]

O array começa com [ e termina com ], e cada parte  é separa por , (vírgula) e podem divergir o tipo de dados. Exemplo:


["Huguinho","Zezinho","Luizinho", 3]

Tanto a estrutura object como o array do JSON podem ser combinadas, formando diversas estruturas de dados.

Exemplo – Um array de objects:


[{ "nome" : "Huguinho", "idade" : 10 },
 { "nome" : "Zezinho", "idade" : 12 },
 { "nome" : "Luizinho", "idade" : 10 }]

Exemplo – Object contendo uma propriedade array:


{"tio" : "Pato Donald",
 "idade" : 40,
 "sobrinhos" :
        [{ "nome" : "Huguinho",     "idade" : 10 },
          { "nome" : "Zezinho", "idade" : 12 },
          { "nome" : "Luizinho", "idade" : 10 }]
}

JSON nasceu com um subconjunto da linguagem Javascript para representar objetos e atualmente qualquer linguagem de programação moderna tem suporte (via pacotes de terceiros) a esse formato de troca de informação.

Os sites jsonviewer.stack.hu e  jsonformatter.curiousconcept.com/ são bons lugares para validar a estrutura JSON

Num futuro post demonstrarei o uso do JSON com ASP.NET em chamada assíncronas.

Drag and drop (Dnd) com HTML5

hrml5draganddropUm recurso bacana que é visto em alguns site é o recurso de selecionar um item e arrastá-lo para outra área na mesma página. Este recurso é chamado de Drag and drop, e no HTML5 ele é nativo, dispensando o uso de bibliotecas de terceiros.
Para iniciar, precisamos definir um elemento HTML como “de origem” que será o elemento arrastável, e um elemento de destino, que receberá o elemento de origem.
O elemento HTML que deseja ser arrastável deve manter a propriedade draggable habilitada (true).
Por exemplo, desejo que cada item da lista abaixo seja arrastável:
<ul id="ulOpcoes">
    <li draggable="true">Opção 1</li>
    <li draggable="true">Opção 2</li>
    <li draggable="true">Opção 3</li>
    <li draggable="true">Opção 4</li>
    <li draggable="true">Opção 5</li>
    <li draggable="true">Opção 6</li>
</ul>
Um elemento arrastável (draggable=true) tem os seguintes eventos:
  • dragstart: O elemento começou a ser arrastado. A função que vai tratar o evento recebe um parâmetro, que há uma referência ao elemento sendo arrastado.
  • drag: O objeto está sendo arrastado.
  • dragend: A ação de arrastar terminou.

Esses eventos devem ser associados a uma função para tratá-los.

</span></div>
<ul id="ulOpcoes">
    <li draggable="true" ondragstart="onDragStart(event)">Opção 1</li>
    <li draggable="true" ondragstart="onDragStart(event)">Opção 2</li>
    ...

Usando Javascript, podemos associar os eventos a cada LI, sem a necessidade de fazer manualmente como acima.

window.onload = function () {

    //Após a carga completa da página, cada LI é associado à função onDragStart.
    var lis = document.querySelectorAll("#ulOpcoes > li");
    for (var i = 0; i < lis.length; i++) {

        lis[i].addEventListener("dragstart", function (event) { onDragStart(event) });
    }
}

function onDragStart(event) {

    event.dataTransfer.setData("Text", event.target.innerHTML);
}

A função que vai tratar o evento ondragstart recebe um parâmetro, que há uma referência ao elemento sendo arrastado através da propriedade target. E a propriedade dataTransfer, com o uso do método setData, oferece meios de armazenar dados a serem transmitidos ao destino. O primeiro parâmetro da função setData é o tipo mime da informação a ser armazenada (no exemplo, Text) e o segundo parâmetro é a informação (no exemplo, guardei o texto contido dentro do LI). Posteriormente será o usado o tipo mime para recuperar a informação.

Com a origem totalmente programa, agora é hora de pensar no destino. O elemento de destino não precisa de nenhuma propriedade específica, como o de origem. Mas precisa de eventos e funções que saibam como receber o que foi arrastado até ele.

O elemento de destino tem os seguintes eventos:
  • dragenter: O objeto sendo arrastado entrou no objeto de destino.
  • dragleave: O objeto sendo arrastado deixou o objeto de destino.
  • dragover: O objeto sendo arrastado se move sobre o objeto de destino.
  • drop: O objeto sendo arrastado foi solto sobre o objeto de destino.

Neste exemplo, o elemento de destino será outra lista, que deverá receber o texto do item da lista de origem que foi arrastado até ela.

<ul id="ulOpcoesSelecionadas" ondragover="onDragOver(event)" ondrop="onDrop(event)">
</ul>

O evento ondrop será o responsável por tratar e receber o item arrastável. A função associada ao evento recebe por parâmetro informações sobre o destino, e também a informação guardada na propriedade dataTransfer armazenada anteriormente sob o tipo mime. O método getData precisa do tipo mime armazenado para poder recuperar a informação (como no exemplo a seguir, Text).

function onDrop(event) {
    var li = document.createElement("li")
    li.innerHTML = event.dataTransfer.getData("Text");
    document.getElementById('ulOpcoesSelecionadas').appendChild(li);
}

E por fim, para que tudo funcione corretamente, é necessário mudar o comportamento padrão do navegador. Por padrão, dados/elementos não podem ser soltos em outros elementos. Para permitir um “drop”, devemos mudar o tratamento padrão do elemento de destino.

E isso é feito na função que trata o evento ondragover do elemento de destino, que é disparada quando o objeto sendo arrastado se move sobre o objeto de destino.

function onDragOver(event)
{
    event.preventDefault();
}

O evento envia a função informações sobre o destino, e o método preventDefault() do parâmetro cancela o comportamento padrão do navegador, e assim permitindo o drop.

O exemplo completo e com exemplos de uso de todos os eventos pode ser baixado aqui.

E é isso….

 

Até mais.

Usando a API WebStorage da Open Web Plataform (HTML5 e seus amigos)

HTML5_Logo_512Em HTML5 é possível armazenar dados no lado do cliente no formato pares de valor de chave, de forma simular como é feito com as Cookies, só que mais fácil. Normalmente é a linguagem de servidor quem cria e envia as Cookies ao cliente.
Com a API de Storage tudo é manipulado diretamente no cliente por Javascript, não há interferência do servidor.
A API WebStorage disponibiliza duas formas para armazenamento no cliente: SessionStorage e LocalStorage.

sessionStorage
: armazenamento de dados independente (não compartilhado entre janelas/guias). Os dados são excluídos quando o usuário fecha a janela/guiado navegador.

localStorage: armazenamento de dados compartilhado entre janelas (comportamento semelhante ao do cookie). Mesmo fechando o navegador, os dados ficam armazenados e somente serão apagados se o cache for limpo ou se solicitada sua exclusão via programação JS.

Vamos aos exemplos.
A ideia aqui é armazenar o que o usuário informou no formulário HTML abaixo usando as duas maneiras apresentadas acima, e depois recuperar a informação.
<textarea id="texto" rows="5" cols="5"></textarea>
<br />
<input type="button" value="Salvar no cliente" onclick="salvar()"/>
<input type="button" value="Recuperar no cliente" onclick="recuperar()"/>

O evento onclick do primeiro input button vai disparar a função salvar(), que tem por objetivo salvar os dados no cliente usando o método setItem da propriedade localStorage. Vamos ao código.

    function salvar() {
        localStorage.setItem('teste', texto.value);
    }

E evento onclick do segundo input button vai disparar a função recuperar(), que vai acessar o valor salvo através do método getItem da propriedade localStorage e devolvê-lo para seu respectivo input.

    function recuperar() {
        document.getElementByI('texto').value = localStorage.getItem('teste');
    }

Usando a Ferramenta de Desenvolvedores do Google Chrome é possível inspecionar o que está armazenado localmente.

localstorage

A nível de programação, para usar a SessionStorage não muda quase nada. Ao invés de usar a propriedade localStorage, deve usar sessionStorage. E os métodos setItem e getItem continuam com o mesmo objetivo, adicionar e remover valores.

Quando usado Cookie, ela é trafegada sempre entre cliente e servidor pelo protocolo HTTP. Isso não ocorre com esta API, a informação é exclusivamente mantida no cliente, e nunca “sobe” para o servidor.

Outros dois métodos importantes disponibilizados são o removeItem, e clear. O primeiro remove o item de nome informado no parâmetro e o segundo, limpa todos os itens do domínio. Ambos funcionam tanto no localStorage como no sessionStorage.

Usando a API de Geolocalização da Open Web Plataform (HTML5 e seus amigos)

HTML5_Logo_512A API Geolocation da Open Web Plataform  permite via Javascript solicitar ao navegador a localização real do usuário. As informações de localização podem ser usadas para exibir mapas, direções e outras informações relevantes a posição global do usuário.

Os navegadores que suportam a API definem a propriedade navigator.geolocation que oferece três métodos:

  1. navigator.geolocation.getCurrentPosition(): solicita a posição atual do usuário.
  2. navigator.geolocation.watchPosition(): solicita a posição atual do usuário e continua a monitorar.
  3. navigator.geolocation.clearWatch(): para de monitorar a posição do usuário.

Abaixo demonstro um pequeno exemplo de como recuperar a geolocalização do usuário e mostrar um mapa no Google e no Bing Maps com a respectiva localização do usuário.


//Usando do método getCurrentPosition para recuperar a localização atual do usuário.
navigator.geolocation.getCurrentPosition(function (posicao) { localizacao(posicao) },
            function (erro) { mostraErro(erro) });

//Função de Callback do sucesso do método getCurrentPosition
function localizacao(posicao) {
    alert('Lat: ' + posicao.coords.latitude + ' ' + 'Lon: ' + posicao.coords.longitude);

    //Abrindo o mapa no bing maps
    window.open("http://www.bing.com/maps/?v=2&where1=" + posicao.coords.latitude + "," +
posicao.coords.longitude + "&encType=1","");

    //Abrindo o mapa no google maps
    window.open("http://maps.googleapis.com/maps/api/staticmap?center=" +
posicao.coords.latitude + "," + posicao.coords.longitude +
"&zoom=14&size=400x300&sensor=false");
}

//Função de Callback para falhas método getCurrentPosition
function mostraErro(erro)
{
    switch (erro.code) {
        case erro.PERMISSION_DENIED:
            alert("user did not share geolocation data");
            break;
        case erro.POSITION_UNAVAILABLE:
            alert("could not detect current position");
            break;
        case erro.TIMEOUT:
            alert("retrieving position timed out");
            break;
        default:
            alert("unknown error");
            break;
    }
}

Infelizmente não é exato pois, pois a API usa informações dos provedores de internet a qual o usuário está conectado.

E é isso. As possibilidades são várias.

CKEditor: Como identificar quando está totalmente carregado.

Não sei porque, mas sempre apanho do CKEditor. Hehehe.

Dependendo da situação e da lógica aplicada numa página que usa o CKEditor, é necessário acessar suas respectivas instâncias logo após terem sido totalmente carregadas pelo navegador  e disponíveis para interação.

Para exemplificar, o código abaixo demonstra como aumentar a altura do CkEditor logo após ter sido carregado.

<script type="text/javascript">
	CKEDITOR.on('instanceReady', function (e) {
		e.editor.resize('100%', 550);
	});
</script>