107 votes

InnerHTML est-il asynchrone?

J'espère que je ne vais pas faire un fou de moi-même, mais j'essaie de comprendre ce qui se passe dans ces deux lignes de code:

document.body.innerHTML = 'something';
alert('something else');

Ce que j'observe, c'est que l'alerte s'affiche avant le HTML a été mis à jour (ou peut-être qu'il a, mais la page n'a pas été actualisé/repeint/whatever)

Caisse codepen pour voir ce que je veux dire.

Veuillez noter que même en mettant alert en setTimeout(..., 0) n'aide pas. Regarde comme il faut plus d'une boucle d'événement pour l' innerHTML de en fait de mise à jour de la page.

EDIT:

J'ai oublié de mentionner que je suis en utilisant google Chrome et n'ai pas vérifié les autres navigateurs. On dirait qu'il est visible uniquement dans le navigateur Chrome. Néanmoins, je suis toujours intéressé pourquoi est-ce qui se passe.

138voto

jered Points 4581

Réglage innerHTML est synchrone, comme le sont la plupart des changements que vous pouvez faire pour les DOM. Toutefois, le rendu de la page web est une autre histoire.

(Rappelez-vous, DOM signifie "Document Object Model". C'est juste un "modèle", une représentation de données. Ce que l'utilisateur voit sur son écran est une image de la façon dont ce modèle devrait ressembler. Donc, en changeant le modèle n'est pas instantanément changer l'image - il prendre le temps de mise à jour.)

L'exécution de JavaScript et de rendu de la page web effectivement se produire séparément. Pour le mettre simplement, d'abord tous de JavaScript sur la page de pistes (à partir de la boucle d'événements - découvrez cette excellente vidéo pour plus de détails) et ensuite, après que le navigateur rend toutes les modifications apportées à la page web de l'utilisateur pour voir. C'est pourquoi le "blocage" est une grosse affaire, - l'exécution de calcul intensif code empêche le navigateur de la "JS" de l'étape et dans la "le rendu de la page" de l'étape, provoquant la page de geler ou de bégayer.

Chrome pipeline ressemble à ceci:

enter image description here

Comme vous pouvez le voir, tous les JavaScript qui se produit en premier. Puis la page est de style, dessiné, peint, et composition - le "rendu". Pas tous de ce pipeline sera exécutée à chaque frame. Cela dépend de ce que les éléments de la page a changé, le cas échéant, et comment ils doivent être réaffichées.

Remarque: alert() est également synchrone et exécute pendant le JavaScript étape, c'est pourquoi la boîte de dialogue d'avertissement s'affiche avant de voir les modifications apportées à la page web.

Vous pouvez maintenant demander "tiens, qu'est-ce exactement est exécuté dans que 'JavaScript' étape dans le pipeline? Fait tout mon code exécuté à 60 fois par seconde?" La réponse est "non", et il va revenir à la façon dont la JS boucle d'événement de travaux. Code JS ne fonctionne que si il est dans la pile de choses comme des écouteurs d'événement, les délais d'attente, que ce soit. Voir la vidéo précédente (vraiment).

https://developers.google.com/web/fundamentals/performance/rendering/

28voto

d-_-b Points 3491

Oui, il est synchrone, car cela fonctionne (allez-y, tapez-le dans votre console):

 document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert
 

La raison pour laquelle vous voyez l'alerte avant de voir la page changer est que le rendu du navigateur prend plus de temps et n'est pas aussi rapide que votre javascript qui s'exécute ligne par ligne.

6voto

apsillers Points 29372

L' innerHTML de la propriété réelle est mis à jour de manière synchrone, mais le visuel redessiner que ce changement provoque se passe de manière asynchrone.

Le rendu visuel de la DOM est asynchrone en Chrome et n'aura pas lieu jusqu'à ce que après la fonction JavaScript de la pile est désactivée et que le navigateur est libre d'accepter un nouvel événement. D'autres navigateurs peuvent utiliser des threads pour gérer le code JavaScript et le navigateur de rendu, ou ils peuvent laisser certains événements obtenir prioritaire, tandis qu'une alerte est l'arrêt de l'exécution d'un autre événement.

Vous pouvez voir cela de deux manières:

  1. Si vous ajoutez for(var i=0; i<1000000; i++) { } avant votre alerte, vous avez donné le navigateur beaucoup de temps pour faire un nouveau dessin, mais il n'a pas, parce que la fonction de la pile n'a pas effacé (add est toujours en cours d'exécution).

  2. Si vous retardez votre alert via asynchrone setTimeout(function() { alert('random'); }, 1), le redessiner processus sera d'aller de l'avant de la fonction retardée par setTimeout.

    • Cela ne fonctionne pas si vous utilisez un délai d'attente de 0, peut-être parce que Chrome donne événement-file d'attente de priorité 0 délais d'attente à l'avance de tout autre événement (ou au moins à l'avance de redessiner les événements).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X