J’essaie de corriger du javascript peu performant dans une interface utilisateur lente, et j’ai réduit la cause principale à un .width()
jQuery .width()
utilisé pour afficher la taille réelle en pixels d’un élément width: 100%
dans un responsive mise en page, dans un processus qui doit souvent se produire en réponse aux actions de l’utilisateur.
J’ai ajouté des mesures basées sur l’horodatage et elles montrent que cela représente à lui seul environ 33% du temps de latence, ce qui rend la différence entre une sensation d’interface utilisateur nette et une impression de lenteur de l’interface utilisateur. En supprimant cette ligne, l’interface utilisateur est rapide – mais elle place les choses au mauvais endroit …
Il semble bien établi que .width()
est relativement lent dans jQuery> 1.8 principalement pour deux raisons:
Il force la refusion lors du calcul de la taille de l’élément . Extrait d’un article cité à quel moment la refusion se produit-elle dans un environnement DOM? :
[le refoulement se produit lorsque] vous récupérez une mesure à calculer, telle que l’access à offsetWidth, clientHeight ou à une valeur CSS calculée (via getComputedStyle () dans les navigateurs compatibles DOM ou currentStyle dans IE)
… en fait, pour les navigateurs comme IE et Firefox qui retardent les modifications DOM jusqu’au dernier moment afin d’éviter des modifications contradictoires (par exemple, masquer et afficher dans le même appel de fonction), les utilisateurs ajoutent parfois des getters d’état inutiles afin de forcer la redissortingbution se produire .
Il doit également vérifier l’état de l’élément border-box. De leur blog :
jQuery 1.8 doit maintenant vérifier la propriété box-sizing chaque fois que vous utilisez .width () afin de pouvoir décider si elle doit soustraire le remplissage et la largeur de la bordure. Cela peut coûter cher – jusqu’à 100 fois plus cher sur Chrome!
Le but de l’appel width()
de mon code est de voir si, et dans quelle mesure, une conception réactive a été réduite. Il doit examiner l’élément wrapper d’un widget, qui a la width: 100%;
(mais peut se trouver dans une colonne ou un autre conteneur, en fonction du site / de la page qui l’héberge), et doit voir quel% de la largeur maximale de ce wrapper est réellement affiché.
Un autre code basé sur un système de coordonnées différent me donne l’emplacement, en pixels, d’une étiquette, puis je dois utiliser un facteur de mise à l’échelle (essentiellement = $wrapper.width() / maxWidth;
) pour réduire l’emplacement afin que Par exemple, si la page est affichée dans une fenêtre / un périphérique étroit et que le wrapper correspond à 50% de sa taille maximale, les décalages supérieur et gauche des libellés correspondent à 50% de leurs valeurs par défaut.
Existe-t-il un moyen quelconque d’accéder à ces données pour savoir combien un élément% -width a été réduit sans provoquer de refusion et les autres choses qui .width()
appels .width()
?
Choses que j’ai essayées ou exclues:
.outerWidth()
est exactement aussi lent que .width()
.get(0).clientWidth
(l’option purement Javascript / non-Jquery) est aussi presque aussi lent que .width()
(vraisemblablement, c’est donc le refoulement qui est à l’origine du problème) .get(0).clientWidth
suivi de l’un des .outerHeight()
dans l’autre dimension (par exemple .get(0).clientWidth
suivi de .outerHeight()
), les appels après le premier sont très rapides (~ 20 fois). plus rapide). Vraisemblablement, étant donné que la redissortingbution vient d’être effectuée et que les propriétés des éléments viennent d’être consultées, elles sont en quelque sorte mises en cache. Mais l’effet ne tient pas pour les appels répétés à la fonction, mais dans un appel de fonction. .css("width")
sert évidemment à rien car cela me donnerait 100%
dans tous les cas [ Mise à jour ] Je pensais avoir trouvé un moyen de contourner mon besoin de résoudre le problème et de positionner mes étiquettes sans accéder à la mise à l’échelle de l’élément: comme j’avais déjà la variable maxWidth
en pixels et les décalages en pixels, j’en avais assez data pour calculer un pourcentage de décalage pour mes étiquettes avec leftOffset_px / maxWidth_px
et topOffset_px / maxHeight_px
, puis + '%'
et l’appliquer comme décalage top
et left
CSS de chaque étiquette. C’est ridiculement plus rapide – maintenant moins de 1 milliseconde, donc vite ma fonction basée sur l’horodatage ne peut pas le mesurer!
Malheureusement, j’ai aussi une autre fonction qui vérifie que les étiquettes, qui ont une largeur fixe, ne débordent pas le conteneur sensible, et pour cela, je dois prendre en compte la largeur de pixel actuelle du conteneur ou son facteur d’échelle. .
Vous ne savez pas trop à quel point cela pourrait être une amélioration, mais vous pouvez essayer d’append un élément positionné de manière absolue, ne contenant aucun enfant, à la racine de votre widget, dans le seul but de lire sa largeur. Je pense que les éléments en position absolue ne font que rediffuser ses enfants
.root { position: relative; } .ruler { position: absolute; width: 100%; }
_
–
var updatedWidth = $('.ruler').width()
(Bien que je sois d’accord avec les commentaires disant que vous devriez essayer de résoudre avec CSS)