Espero não fazer papel de bobo, mas estou tentando entender o que está acontecendo nessas duas linhas de código:
document.body.innerHTML = 'something';
alert('something else');
O que estou observando é que o alerta é mostrado antes que o HTML tenha sido atualizado (ou talvez sim, mas a página não foi atualizada / repintada / qualquer coisa)
Verifique este código para ver o que quero dizer.
Por favor, note que, mesmo colocando alert
em setTimeout(..., 0)
não ajuda. Parece que são necessários mais loops de eventos para innerHTML
realmente atualizar a página.
EDITAR:
Esqueci de mencionar que estou usando o Chrome e não verifiquei outros navegadores. Parece que só é visível no Chrome. No entanto, ainda estou interessado por que isso está acontecendo.
javascript
html
google-chrome
dom
cada um da barra
fonte
fonte
Respostas:
A configuração de innerHTML é síncrona, assim como a maioria das alterações que você pode fazer no DOM. No entanto, renderizar a página da web é uma história diferente.
(Lembre-se de que DOM significa "Document Object Model". É apenas um "modelo", uma representação de dados. O que o usuário vê na tela é uma imagem de como esse modelo deve ser. Portanto, mudar o modelo não é instantâneo alterar a imagem - leva algum tempo para atualizar.)
A execução do JavaScript e a renderização da página da Web acontecem separadamente. Para colocá-lo de forma simplista, em primeiro lugar todo o JavaScript na página runs (do ciclo de eventos - confira este excelente vídeo para mais detalhes) e, em seguida, depois que o navegador processa quaisquer alterações à página da Web para o utilizador ver. É por isso que "bloquear" é tão importante - a execução de código computacionalmente intensivo evita que o navegador passe da etapa "executar JS" e entre na etapa "renderizar a página", fazendo com que a página congele ou gagueje.
O pipeline do Chrome é semelhante a este:
Como você pode ver, todo o JavaScript acontece primeiro. Em seguida, a página é estilizada, disposta, pintada e composta - a "renderização". Nem todo esse pipeline executará todos os quadros. Depende de quais elementos da página foram alterados, se houver, e de como eles precisam ser renderizados novamente.
Observação:
alert()
também é síncrono e executado durante a etapa de JavaScript, por isso a caixa de diálogo de alerta aparece antes de você ver as alterações na página da web.Agora você pode perguntar "Espere aí, o que exatamente é executado nessa etapa de 'JavaScript' no pipeline? Todo o meu código é executado 60 vezes por segundo?" A resposta é "não" e remonta ao funcionamento do loop de eventos JS. O código JS só é executado se estiver na pilha - de coisas como ouvintes de eventos, tempos limite, o que for. Veja o vídeo anterior (realmente).
https://developers.google.com/web/fundamentals/performance/rendering/
fonte
Sim, é síncrono, porque funciona (vá em frente, digite no console):
O motivo pelo qual você vê o alerta antes de ver a alteração da página é que a renderização do navegador leva mais tempo e não é tão rápida quanto a execução do seu javascript linha por linha.
fonte
text
no meu exemplo) Isso vai responder à sua pergunta se é síncrono. A renderização do navegador vs. execução do Javascript é apple and oranges :)A
innerHTML
propriedade real é atualizada de forma síncrona, mas o redesenho visual que essa alteração causa acontece de forma assíncrona.A renderização visual do DOM é assíncrona no Chrome e não acontecerá até que a pilha de funções JavaScript atual tenha sido limpa e o navegador esteja livre para aceitar um novo evento. Outros navegadores podem usar threads separados para manipular o código JavaScript e a renderização do navegador, ou podem permitir que alguns eventos tenham prioridade enquanto um alerta está interrompendo a execução de outro evento.
Você pode ver isso de duas maneiras:
Se você adicionar
for(var i=0; i<1000000; i++) { }
antes do alerta, deu ao navegador bastante tempo para fazer um redesenho, mas não deu, porque a pilha de funções não foi apagada (add
ainda está em execução).Se você atrasar o seu
alert
por meio de um assíncronosetTimeout(function() { alert('random'); }, 1)
, o processo de redesenho irá adiante da função atrasada por setTimeout.0
, possivelmente porque o Chrome dá prioridade à fila de eventos para0
tempos limite antes de quaisquer outros eventos (ou pelo menos antes dos eventos de redesenho).fonte
setTimeout(func, 1)
funcionou todas as vezes, confira este vídeo: youtu.be/r8caVE_a5KQ