Perguntei para vários desenvolvedores web o que aconteceria se um handler onload acrescentasse outro handler onload. Será que o segundo handler onload executa?
O evento onload já foi acionado, por isso pode ser tarde demais para o segundo onload se desencadear. Por outro lado, a fase onload não acabou (estamos entre loadEventStart e loadEventEnd em termos de Navigation Timing), então pode ter uma chance de o segundo handler onload poder ser adicionado a uma fila e executado no final.
Nenhuma das pessoas que perguntei sabia a resposta, mas todos nós tínhamos um palpite. Vou explicar por que isso é importante, mas, até então, resolva a sua resposta – você acha que o segundo onload executa?
Para responder a essa pergunta eu criei a página de testes OnLoad in OnLoad. Ela define um handler onload inicial. Nesse primeiro handler onload, é adicionado um segundo handler onload. Aqui está o código:
function addOnload(callback) { if ( "undefined" != typeof(window.attachEvent) ) { return window.attachEvent("onload", callback); } else if ( window.addEventListener ){ return window.addEventListener("load", callback, false); } } function onload1() { document.getElementById('results').innerHTML += "First onload executed."; addOnload(onload2); } function onload2() { document.getElementById('results').innerHTML += "Second onload executed."; } addOnload(onload1);
Eu criei um teste de usuário Browserscope para registrar os resultados e tuitei pedindo às pessoas para executá-lo. Graças ao crowdsourcing, temos resultados de dezenas de browsers. Até agora, nenhum navegador executa o segundo handler onload.
Por que isso é importante?
Existe uma crescente sensibilização para o impacto negativo que os scripts têm sobre os tempos de carregamento da página. Muitos sites estão seguindo as melhores práticas de desempenho de carregamento de scripts de forma assíncrona. Enquanto essa é uma mudança fantástica que faz as páginas renderizar mais rapidamente, ainda é possível para um script assíncrono tornar as páginas mais lentas porque o onload não dispara até que todos os scripts assíncronos tenham sido baixados e executados.
Para atenuar o impacto negativo no desempenho dos scripts, alguns sites foram transferidos para os scripts de carga em um handler onload. O problema é que muitas vezes os scripts que estão sendo transferidos para o handler onload são scripts de terceiros. Combine isso com o fato de que muitos scripts de terceiros, especialmente métricas, dão o pontapé inicial de sua execução por meio de um handler onload. O resultado final é que nós estamos carregando os scripts que incluem um handler onload em um handler onload. Sabemos, a partir dos resultados do teste acima, que isso resulta no segundo handler onload não sendo executado, o que significa que o script de terceiros não vai completar toda a sua funcionalidade.
Os scripts (especialmente scripts de terceiros) que usam manipuladores onload devem, portanto, verificar se o evento onload já foi acionado. Se sim, então em vez de usar um handler onload, a execução de script deve começar imediatamente. Um bom exemplo disso é a minha biblioteca Episodes RUM. Anteriormente, eu iniciava a coleta das métricas RUM por meio de um handler onload, mas agora episodes.js também verifica document.readyState para garantir que as métricas estejam reunidas mesmo se o onload já tiver sido acionado. Eis o código:
if ( "complete" == document.readyState ) { // The page is ALREADY loaded - start EPISODES right now. if ( EPISODES.autorun ) { EPISODES.done(); } } else { // Start EPISODES on onload. EPISODES.addEventListener("load", EPISODES.onload, false); }
Resumindo
- Se você tem um site e quer fazer tudo certinho para um script não afetar os tempos de carregamento da página, considere colocá-lo em um handler onload. Ao fazer isso, certifique-se de testar se o script atrasado não depende de um handler onload para completar sua funcionalidade (outra opção é carregar o script em um iframe, mas scripts de terceiros podem não funcionar corretamente dentro de um iframe).
- Se você possui um script de terceiros que acrescenta um handler onload, talvez você queira aumentar, verificando document.readyState para se certificar de que o onload não tenha sido disparado ainda.
***
Artigo traduzido pela Redação iMasters com autorização do autor. Publicado originalmente em http://www.stevesouders.com/blog/2014/09/12/onload-in-onload/