sexta-feira, 30 de outubro de 2009

Comet no IIS

Comet é uma metodologia que requer um poder de processamento concorrente muito grande dos servidores. Até o momento foram lançado alguns servidores próprios para a abordagem, porém nada ainda voltado para Microsoft IIS, ficando difícil de programadores .NET usufruirem a tecnologia. WebSync vem para preencher essa lacuna. Ele foi desenvolvido C#, roda com o IIS e foi testado numa máquina acer de U$500,00 com 30.000 usuários concorrentes e 25.000 mensagens e rodou perfeitamente! Vejam mais detalhes no post completo do ajaxian.com. P.S.: Sugiro assistirem o vídeo explicativo.

quinta-feira, 24 de setembro de 2009

10 úteis dicas de usabilidade

Todos concordariam que usabilidade é um aspecto importante de Web Design. Seja trabalhando em um website de portfólio, loja online ou aplicação web, fazer as páginas fáceis e agradáveis para seus visitantes usarem é fundamental. Muitos estudos foram feitos ao passar dos anos sobre vários aspectos da Web e Design de interfaces, e os resultados são valiosos para nos ajudar a melhorar o nosso trabalho. Aqui estão 10 resultados sobre usabilidade que podem ajudar a melhorar a experiência do usuário em seu site.

quarta-feira, 23 de setembro de 2009

Combinando arquivos Javascript e CSS de forma descomplicada

Essa é a proposta do Javascript Combiner: agrupar diversos arquivos respeitando dependências.

A maioria dos sistemas que vi requerem que você indique as dependências entre arquivos em um arquivo separado. Isso me aborreceu por muito tempo. Porque as informações de dependência deve existir fora do arquivo que as utiliza? Porque introduzir um outro arquivo cuja única tarefa é gerenciar dependências? O que eu queria era um equivalente do #include para C ou import do Java, algo que me permita especificar dependências no próprio arquivo fonte e depois combinar todos juntos respeitando a ordem de inclusão. Então no começo do ano passado comecei a trabalhar no Javascript Combiner.

Exemplo de declaração de um arquivo importado

/*requires yahoo.js*/

Veja mais no post original.

terça-feira, 15 de setembro de 2009

SpriteMe! Geração de CSS Sprite como nunca visto


Anunciado esta semana a criação da mais nova ferramenta para geração de CSS Sprites, o SpriteMe. Os sprites são gerados de forma extremamente dinâmica enquanto você navega

terça-feira, 1 de setembro de 2009

Você acha que sabe desenvolver RIA?


Publico hoje uma apresentação de slide muito interessante, apresentada por Theresa Neil no evento DelveUI de desenvolvimento de interfaces web. Na apresentação ela cita os componentes de uma interface de aplicação rica (RIA), além de listar uma série de modelos de como construir determinada visualização da forma mais correta. Link para o post oficial aqui.

quarta-feira, 26 de agosto de 2009

Como carregar Javascript dinâmicamente

O conceito de "aplicação de uma página" foi introduzido juntamente com Ajax. São aplicações consagradas como o gmail em que você entra numa página index.php (default.aspx, etc...) e nunca mais é redirecionado. Tudo é montado dinâmicamente usando Javascript e Ajax. Em sistemas assim incluir todos os scripts em uma página só torna o carregamento da aplicação pesado e demonstra-se uma prática inviável. Solução: carregar fontes javascript sob demanda. Aqui publico então alguns recursos para implementar esse conceito e dar uma turbinada no seu sistema.

google.load

A google possui um método para carregar APIs Ajax dinâmicamente. Único inconveniente é que é um método específico da google e não pode ser usado para carregar um script da sua aplicação. Esse método está disponível dentro de http://www.google.com/jsapi em um código compactado.
O recurso mais interessente, e que deve estar presente em todos os métodos de carregamento dinâmico, é a opção de monitorar quando o script está carregado. Mais sobre o assunto pode ser visto na documentação oficial.
<script type="text/javascript">
google.load("maps", "2");
google.load("search", "1");

// Call this function when the page has been loaded
function initialize(){
var map = new google.maps.Map2(document.getElementById("map"));
map.setCenter(new google.maps.LatLng(37.4419, -122.1419), 13);

var searchControl = new google.search.SearchControl();
searchControl.addSearcher(new google.search.WebSearch());
searchControl.addSearcher(new google.search.NewsSearch());
searchControl.draw(document.getElementById("searchcontrol"));
}

google.setOnLoadCallback(initialize);
</script>

Javascript Simple Loader

Encontrei esse código publicado no snipplr.com. Sem nenhum comentário, nem observações do autor. Mas parece simples de usar. Basta informar o scr e opcionalmente uma função de callback:
function loadScript(src, callback){
var scriptTag = document.createElement("scriptTag")
scriptTag.type = "text/javascriptTag";
if (scriptTag.readyState) {
//IE
scriptTag.onreadystatechange = function(){
if (scriptTag.readyState == "loaded" ||
scriptTag.readyState == "complete") {
scriptTag.onreadystatechange = null;
setTimeout(function(){
scriptTag.parentNode.removeChild(scriptTag)
}, 1)
callback();
}
};
}
else {
//Others
scriptTag.onload = function(){
setTimeout(function(){
scriptTag.parentNode.removeChild(scriptTag)
}, 1)
callback();
};
}
scriptTag.src = src;
document.getElementsByTagName("head")[0].appendChild(scriptTag);
}

O melhor jeito

Em complemento li um artigo de Nicholas Zakas em que ele expõe, segundo sua opinião, a melhor forma de carregar javascript. Na realidade, ele fez uma análise de outro artigo Steve Souders, que também disponibilizo o link porque o artigo é incrível. Enfim, Nicholas explica que quando incluímos um <script> no código html, o browser ao executar a página, tem que parar e esperar o conteúdo do <script> ser carregado para depois continuar e renderizar a página. Usando carregamento de javascript com o próprio javascript, os códigos são carregados em paralelo, sem travar o browser, fazendo com a página renderize muito mais rápido. Sendo assim ele propõe o seguinte modelo: carregar somente a função de carregamento dinâmico, e usar essa função para carregar todo o resto:
function loadScript(url, callback){

var script = document.createElement("script")
script.type = "text/javascript";

if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}

script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
Mais detalhes podem ser vistos no post oficial.

Enfim, espero ter lhe ajudado a carregar javascripts dinâmicamente. Fica aqui algumas abordagens e links para que você possa encontrar ainda mais conteúdo sobre o assunto. Até a próxima.

sexta-feira, 7 de agosto de 2009

Tudo sobre Vazamento de Memória Javascript (Memory Leak)

Com o advento da programação Ajax as aplicações deixaram de ser submitadas a cada clique e passaram a permanecer na mesma página por longos períodos de tempo. Nesse tipo de aplicação pequenos problemas com gerenciamento de memória podem formar uma grande dor de cabeça para os usuários da aplicação, que manipulam um sistema lento, e para os programadores, que não sabem o que fazer para resolver o problema. Nesse ponto eu me encontrei semanas atrás, e foi aí que iniciei estudos em busca de soluções para problemas de memory leak. Acabei descubrindo muitas coisas bacanas e portanto aqui escrevo a vocês para publicar tudo que li. Bons estudos!

Memory o que?!

Memory leak é um problema conhecido também por vazamento de memória. Um dos artigos que li foi de Douglas Crockford, guru javascript, e ele resume o conceito dessa forma:

Quando um sistema não gerencia corretamente suas alocações de memória é dito que ele vaza memória. Um vazamento de memória é um bug. Sintomas incluem redução de performance e falhas.

Como ocorre e como Resolver?

O pior caso é (pasmem) no Internet Explorer. Apesar de falar sobre o IE, usaremos esse browser como exemplo, problemas de memórias ocorrem em todos os browsers. No IE o sistema de garbage collector (coletor de lixo) não consegue liberar memória quando referências cíclicas ocorrem. Caso você esteja se perguntando o que é referência cíclica, permita-me exemplificar: quando associamos um evento à um elemento DOM, esse elemento guarda a referência para o evento. Caso esse evento utilize o elemento DOM, em alguma referência, uma estrutura cíclica se forma, da qual não é liberada na memória pelo IE.

Referência Circular

<html>
<head>
<script language="JScript">

var myGlobalObject;

function SetupLeak()
{
// First set up the script scope to element reference
myGlobalObject =
document.getElementById("LeakedDiv");

// Next set up the element to script scope reference
document.getElementById("LeakedDiv").expandoProperty =
myGlobalObject;
}


function BreakLeak()
{
document.getElementById("LeakedDiv").expandoProperty =
null;
}
</script>
</head>

<body onload="SetupLeak()" onunload="BreakLeak()">
<div id="LeakedDiv"></div>
</body>
</html>

O problema

Um exemplo de problema de vazamento por referência circular é facilmente vísivel num pequeno teste criado por Douglas. No primeiro exemplo ele cria 10.000 elementos DOM (span) e os remove em seguida. Se você acompanhar o consumo de memória pelo gerenciador de tarefas do windows verá que o consumo e mantém estável.

function makeSpan(n) {
var s = document.createElement('span');
document.body.appendChild(s);
var t = document.createTextNode(' ' + n);
s.appendChild(t);
return s;
}

function process(n) {
queue.push(makeSpan(n));
var s = queue.shift();
if (s) {
s.parentNode.removeChild(s);
}
}

No segundo exemplo ele faz a mesma coisa, porém para cada elemento ele associa um evento, e dentro desse evento utiliza a referência para o elemento. Agora é possível ver o consumo de memória aumentando cada vez mais.

function makeSpan(n) {
var s = document.createElement('span');
document.body.appendChild(s);
var t = document.createTextNode(' ' + n);
s.appendChild(t);
s.onclick = function (e) {
s.style.backgroundColor = 'red';
alert(n);
};
return s;
}

Neste momento estou utilizando Internet Explorer 7.0.5730.13 e o erro ainda ocorre. Existe já o registro do bug no suporte da microsoft e eles dizem terem corrigido. Esse erro pode parecer banal para aplicações que usam submit a cada nova página do sistema, mas com o crescente uso de Ajax em aplicações e sites que nunca submitam são realidade.

A solução

Por segurança devemos nós resolver esse problema, já que o IE7 vai demorar um pouco para ser abandonado. Segundo a própria Microsoft, closures são os responsáveis por esse vazamento. Douglas propõe uma solução útil, porém não 100% segura:

function purge(d) {
var a = d.attributes, i, l, n;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
n = a[i].name;
if (typeof d[n] === 'function') {
d[n] = null;
}
}
}
a = d.childNodes;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
purge(d.childNodes[i]);
}
}
}
Refatorando o exemplo para não gerar mais vazamentos:
function process(n) {
queue.push(makeSpan(n));
var s = queue.shift();
if (s) {
purge(s);
s.parentNode.removeChild(s);
}
}

Não é 100% segura porque ele mesmo nos avisa que eventos associados através do método attachEvent não serão coletados. Isso porque sua referência não é guardada para acesso do programador. Como não podemos acessar, não podemos remover. A não ser que guardamos a referência, aí podemos manualmente retirar o evento com detachEvent, e tudo fica resolvido (veremos essa solução adiante).

Closures

<html>
<head>
<script language="JScript">

function AttachEvents(element)
{
// This structure causes element to ref ClickEventHandler
element.attachEvent("onclick", ClickEventHandler);

function ClickEventHandler()
{
// This closure refs element
}
}

function SetupLeak()
{
// The leak happens all at once
AttachEvents(document.getElementById("LeakedDiv"));
}

function BreakLeak()
{
}
</script>
</head\>

<body onload="SetupLeak()" onunload="BreakLeak()">
<div id="LeakedDiv"></div>
</body>
</html>

O problema

Outro artigo que li era de um membro da equipe de desenvolvimento do IE, Justin Rogers. Ele resume o problema de vazamentos com closures muito bem:

Com referências circulares normais nós temos 2 objetos concretos segurando um a referência do outro, mas com closures é diferente. Além de fazer referência diretamente, elas são feitas importando informações do escopo da sua função pai. Normalmente uma variável global da função, e parâmetros utilizados quando a função é invocada existem somente pelo ciclo de vida da função em si. Com closures essas variáveis e paramêtros continuam a ter uma referência prolongada enquanto a closures está viva; e como closures podem permaner vivas além do tempo de vida de suas funções pais, o mesmo ocorre com qualquer uma dessas variáveis e paramêtros.

A solução

Nesse caso a solução não é tão óbvia assim. Isso porque usamos uma função anônima, não guardamos sua referência e por isso não podemos removê-la. Uma solução proposta por Scott Isaacs em seu blog é guardar a referência da função no elemento para depois poder remover:

function DoThis()
{
var el = document.createElement("div");

el.attachEvent("onclick",DoThis);
window.attachEvent("onunload",Cleanup);

function DoThis()
{
alert("clicked");
}

function Cleanup()
{
el.detachEvent("onclick",DoThis);
window.detachEvent("onunload",Cleanup);
el = null;
}
}

Concluindo

Na realidade um assunto como esse deve ser praticado e estudado constantemente. Acredito não ter escrito um guia completo mas ao menos ter conseguido lhe colocar em um rumo muito melhor de desenvolvimento. Ainda irei abordar mais sobre isso aqui no framebox, mas por enquanto fiquem com essas dicas e alguns links de recursos que utilizei. Forte abraço e até o próximo post.

Referências

quarta-feira, 5 de agosto de 2009

Rotacionando texto com CSS

Algumas vezes quis fazer isso mas não sabia como. Essa semana vi no blog de Jonathan Snook uma solução usando 100% CSS que funciona em todos browsers modernos, incluindo IE =D
<div class="example-date">
<span class="day">31</span>
<span class="month">July</span>
<span class="year">2009</span>
</div>

-webkit-transform: rotate(-90deg); 
-moz-transform: rotate(-90deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);

segunda-feira, 3 de agosto de 2009

Aprenda o que é Javascript Closures


Muito tempo atrás (o segunto post do blog) eu abordei um tema muito bacana de Javascript: Closures. Alguns dias atrás, encontrei uma outra abordagem do assunto, um tanto quanto informativa e de nome cômico. Morris Johns é o autor de Javascript Closures for Dummies, uma abordagem completa de como dominar esse recurso poderoso de Javascript. Ele começa testando nossos conhecimentos:


Este artigo é destinado a programadores com alguma experiência, e que consegue ler a seguinte função Javascript :
function sayHello(name) {

var text = 'Hello ' + name;

var sayAlert = function() { alert(text); }

sayAlert();

}

E continua com uma série de exemplos e explicações como este:


function sayAlice() {

var sayAlert = function() { alert(alice); }

// Local variable that ends up within closure
var alice = 'Hello Alice';

return sayAlert;
}

Infelizmente o artigo está em inglês. Para os que não simpatizam com o idioma sugiro ainda sim checar o site porque os exemplos explicam tudo.

quinta-feira, 30 de julho de 2009

JSONP e vazamento de memória

Neil Fraser fez um ótimo post em seu blog falando sobre como a técnica de carregamento de javascript dinâmico JSONP pode causar vazamentos de memória nos browsers.

JSONP é o nome da técnica onde criamos um elemento script, definimos o src e inserimos no head da página, ocasionando assim um carregamento dinâmico do seu conteúdo:

//cria elemento script
var script = document.createElement('script');
script.src = 'http://example.com/cgi-bin/jsonp?q=What+is+the+meaning+of+life%3F';
script.id = 'JSONP';
script.type = 'text/javascript';
script.charset = 'utf-8';

//adiciona no head, ocasionando seu carregamento
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);

Não entrarei em detalhes, tudo isso funciona muito bem. O problema é que depois de alguns carregamentos o header da sua página pode estar cheio de tags <script>. Uma boa solução seria remover o elemento, assim que seu conteúdo foi extraido:

// Remove velhas tags scripts
var script;
while (script = document.getElementById('JSONP')) {
script.parentNode.removeChild(script);
}

O problema, segundo Neil, é que apesar do browser se livrar do elemento, o objeto dele continua ocupando espaço em memória. Neil então propõe uma solução que diz funcionar perfeitamente:

// Remove velhas tags scripts
var script;
while (script = document.getElementById('JSONP')) {
script.parentNode.removeChild(script);
// Browsers não coletam isso no garbage colletor.
// Então remove tudo para evitar isso
for (var prop in script) {
delete script[prop];
}
}

Remover o elemento e se livrar de suas propriedades. Enfim, a dica está dada. Mais detalhes podem ser vistos no post oficial.