Explorer les performances front-end au niveau du code | Équipe technique JD Cloud

Préface

J'ai récemment fait de l'optimisation des performances et les méthodes d'optimisation spécifiques sont partout sur Internet, je ne les répéterai donc pas ici.

L'optimisation des performances peut être divisée selon les dimensions suivantes : niveau code, niveau construction et niveau réseau.
Cet article explore principalement les performances frontales au niveau du code et est principalement divisé en quatre sections suivantes.

  • Utilisez CSS au lieu de JS

  • Analyse approfondie de JS

  • Algorithme frontal

  • Couche inférieure de l'ordinateur

Utilisez CSS au lieu de JS

Ici, nous le présentons principalement sous deux aspects : l'animation et les composants CSS.

Animations CSS

Avant la sortie de CSS2, même une simple animation devait être implémentée via JS. Par exemple, le mouvement horizontal du carré rouge ci-dessous :

mouvement horizontal

Code JS correspondant :

let redBox = document.getElementById('redBox')
let l = 10

setInterval(() => {
    l+=3
    redBox.style.left = `${l}px`
}, 50)


La spécification CSS2 de 1998 définissait certaines propriétés d'animation, mais en raison des limitations de la technologie des navigateurs à l'époque, ces fonctionnalités n'étaient pas largement prises en charge et appliquées.

Jusqu'à l'introduction de CSS3, les animations CSS étaient mieux prises en charge. Dans le même temps, CSS3 introduit également davantage d'effets d'animation, ce qui rend l'animation CSS largement utilisée dans le développement Web actuel.

Alors quelles animations peuvent être réalisées avec CSS3, voici quelques exemples :

  • Transition - La transition est l'un des effets d'animation couramment utilisés dans CSS 3. En transformant certains attributs d'un élément, l'élément peut passer en douceur d'un état à un autre au cours d'une période de temps.

  • Animation - L'animation est un autre effet d'animation couramment utilisé dans CSS3. Il est utilisé pour ajouter des effets d'animation complexes à un élément. Une série de séquences d'animation peut être définie via des images clés (@keyframes).

  • Transformation - Transform est une technologie utilisée dans CSS3 pour obtenir des effets de transformation graphique 2D/3D, notamment la rotation, la mise à l'échelle, le mouvement, le biseau et d'autres effets.

Réécrivez l'exemple ci-dessus en code CSS comme suit :

#redBox {
    animation: mymove 5s infinite;
}

@keyframes mymove
{
    from {left: 0;}
    to {left: 200px;}
}


Le même effet peut être obtenu en utilisant des styles, alors pourquoi pas.

Il convient de souligner que les animations CSS continuent de se développer et de s'améliorer. Avec l'émergence de nouvelles fonctionnalités de navigateur et de versions CSS, les fonctionnalités des animations CSS sont constamment ajoutées et optimisées pour répondre aux besoins d'animation de plus en plus complexes et à une meilleure expérience utilisateur.

Composants CSS

Dans certaines bibliothèques de composants bien connues, la plupart des accessoires de certains composants sont implémentés en modifiant les styles CSS, tels que le composant Space de Vant.

Accessoires Fonction Styles CSS
direction sens d'espacement direction flexible : colonne ;
aligner Alignement aligner les éléments : xxx ;
remplir S'il faut faire de Space un élément de niveau bloc et remplir l'intégralité de l'élément parent affichage : flexible ;
envelopper S'il faut automatiquement envelopper les lignes flex-wrap : envelopper ;

Un autre exemple est le composant Space d'Ant Design .

Accessoires Fonction Styles CSS
aligner Alignement aligner les éléments : xxx ;
direction sens d'espacement direction flexible : colonne ;
taille taille d'espacement écart : xxx ;
envelopper S'il faut automatiquement envelopper les lignes flex-wrap : envelopper ;

Ce type de composant peut être complètement encapsulé dans l'implémentation du mixin SCSS (il en va de même pour LESS), ce qui peut non seulement réduire le volume de construction du projet (la taille du composant Space des deux bibliothèques après gzip est de 5,4k et 22,9 k respectivement), mais améliorent également les performances.

Visualisez le volume d'un composant dans la bibliothèque de composants et accédez à la connexion .

Par exemple, le mixage spatial suivant :

/* 
* 间距
* size: 间距大小,默认是 8px
* align: 对齐方式,默认是 center,可选 start、end、baseline、center
* direction: 间距方向,默认是 horizontal,可选 horizontal、vertical
* wrap: 是否自动换行,仅在 horizontal 时有效,默认是 false
*/
@mixin space($size: 8px, $direction: horizontal, $align: center, $wrap: false) {
    display: inline-flex;
    gap: $size;

    @if ($direction == 'vertical') {
        flex-direction: column;
    }

    @if ($align == 'center') {
        align-items: center;
    }

    @if ($align == 'start') {
        align-items: flex-start;
    }

    @if ($align == 'end') {
        align-items: flex-end;
    }

    @if ($align == 'baseline') {
        align-items: baseline;
    }

    @if ($wrap == true) {
        @if $direction == 'horizontal' {
            flex-wrap: wrap;
        }
    }
}


Les composants similaires incluent la grille, la mise en page, etc.

Parlons des icônes. Vous trouverez ci-dessous la première capture d'écran du composant icône Ant Design. Il en existe beaucoup qui peuvent être facilement implémentés en utilisant uniquement HTML + CSS.

Icône de direction de conception de fourmi

Idées de mise en œuvre :

  • Prioriser la mise en œuvre en utilisant uniquement les styles

  • Si le style seul ne suffit pas, ajoutez d'abord une balise et implémentez-la via cette balise et ses deux pseudo-éléments ::before et ::after

  • Si une seule étiquette ne suffit pas, pensez à ajouter des étiquettes supplémentaires.

Par exemple, pour implémenter un triangle solide prenant en charge quatre directions, vous pouvez y parvenir avec seulement quelques lignes de styles (la capture d'écran ci-dessus montre 4 icônes) :

/* 三角形 */
@mixin triangle($borderWidth: 10, $shapeColor: #666, $direction: up) {
    width: 0;
    height: 0;
    border: if(type-of($borderWidth) == 'number', #{$borderWidth} + 'px', #{$borderWidth}) solid transparent;

    $doubleBorderWidth: 2 * $borderWidth;
    
    $borderStyle: if(type-of($doubleBorderWidth) == 'number', #{$doubleBorderWidth} + 'px', #{$doubleBorderWidth}) solid #{$shapeColor};

    @if($direction == 'up') {
        border-bottom: $borderStyle;
    }

    @if($direction == 'down') {
        border-top: $borderStyle;
    }

    @if($direction == 'left') {
        border-right: $borderStyle;
    }

    @if($direction == 'right') {
        border-left: $borderStyle;
    }
}


En bref, ce qui peut être implémenté avec CSS ne nécessite pas JS . Il a non seulement de bonnes performances, mais traverse également les piles technologiques et même les terminaux.

Analyse approfondie de JS

Après avoir présenté CSS, examinons JS, principalement sous deux aspects : les instructions de base et le code source du framework.

Optimisation des instructions if-else

Comprenez d’abord comment le processeur exécute les instructions conditionnelles. Reportez-vous au code suivant :

const a = 2
const b = 10
let c
if (a > 3) {
    c = a + b
} else {
    c = 2 * a
}


Le flux d'exécution du CPU est le suivant :

Expressions conditionnelles

On voit que lorsque l'instruction 0102 est exécutée, parce que la condition a > 3 n'est pas remplie, elle passe directement à l'instruction 0104 pour exécution ; de plus, l'ordinateur est très intelligent, s'il constate lors de la compilation que a ne peut jamais être supérieur à 3 , il supprimera directement l'instruction 0103, puis l'instruction 0104 deviendra l'instruction suivante, qui sera exécutée directement en séquence, ce qui est l'optimisation du compilateur.

Revenons donc au sujet, s'il existe le code suivant :

function check(age, sex) {
    let msg = ''
    if (age > 18) {
        if (sex === 1) {
            msg = '符合条件'
        } else {
            msg = ' 不符合条件'
        }
    } else {
        msg = '不符合条件'
    }
}


La logique est très simple. Il s'agit de filtrer les personnes ayant un âge > 18 et un sexe == 1. Il n'y a aucun problème avec le code, mais il est trop verbeux. Du point de vue du CPU, deux opérations de saut doivent Lorsque l'âge est > 18 ans, entrez le if-else intérieur pour continuer à juger, ce qui signifie sauter à nouveau.

En fait, nous pouvons directement optimiser cette logique (généralement nous le faisons, mais nous pouvons le savoir mais ne pas savoir pourquoi) :

function check(age, sex){
    if (age > 18 && sex ==1) return '符合条件'
    return '不符合条件'
}


Par conséquent, si la logique peut se terminer plus tôt , elle se terminera plus tôt pour réduire les sauts du processeur.

Optimisation de l'instruction Switch

En fait, il n'y a pas beaucoup de différence entre l'instruction switch et l'instruction if-else, sauf qu'elles sont écrites de différentes manières.Cependant, l'instruction switch a une optimisation spéciale, c'est-à-dire des tableaux.

Reportez-vous au code suivant :

function getPrice(level) {
    if (level > 10) return 100
    if (level > 9) return 80
    if (level > 6) return 50
    if (level > 1) return 20
    return 10
}


Nous le changeons en une instruction switch :

function getPrice(level) {
    switch(level)
        case 10: return 100
        case 9: return 80
        case 8: 
        case 7: 
        case 6: return 50
        case 5:
        case 4: 
        case 3:
        case 2: 
        case 1: return 20
        default: return 10
}


Il semble qu'il n'y ait pas de différence, mais en fait le compilateur l'optimisera dans un tableau, où les indices du tableau sont de 0 à 10. Le prix correspondant aux différents indices est la valeur de retour, c'est-à-dire :

Tableau de commutation

Et nous savons que les tableaux prennent en charge l'accès aléatoire et sont extrêmement rapides.Par conséquent, l'optimisation du commutateur par le compilateur améliorera considérablement l'efficacité d'exécution du programme, ce qui est beaucoup plus rapide que l'exécution des commandes une par une.

Eh bien, j'ai encore besoin d'écrire une stupide instruction if-else. Puis-je simplement écrire tous les commutateurs ?

Non! Étant donné que l’optimisation de switch par le compilateur est conditionnelle, elle nécessite que votre code soit compact, c’est-à-dire continu.

Pourquoi est-ce? Parce que je souhaite utiliser un tableau pour vous optimiser. Si vous n'êtes pas compact, par exemple, votre code est 1, 50, 51, 101, 110, je vais créer un tableau d'une longueur de 110 pour vous stocker. Uniquement ces positions sont utiles. , n'est-ce pas une perte de place !

Par conséquent, lorsque nous utilisons switch, nous essayons de nous assurer que le code est un type numérique compact.

Optimisation des instructions de boucle

En fait, les instructions de boucle sont similaires aux instructions conditionnelles, mais elles sont écrites de différentes manières. Le point d'optimisation des instructions de boucle est principalement de réduire les instructions.

Voyons d’abord comment écrire la deuxième année :

function findUserByName(users) {
   let user = null
   for (let i = 0; i < users.length; i++) {
       if (users[i].name === '张三') {
           user = users[i]
       }
   }
   return user
}


Si la longueur du tableau est de 10 086 et que la première personne s'appelle Zhang San, alors les 10 085 prochains parcours seront vains et le processeur n'est vraiment pas utilisé en tant qu'être humain.

Tu ne pourrais pas l'écrire comme ceci :

function findUserByName(users) {
    for (let i = 0; i < users.length; i++) {
        if (users[i].name === '章三') return users[i]
    }
}


Ceci est très efficace en écriture et très lisible, et cela est également conforme à notre point de vue mentionné ci-dessus selon lequel si la logique peut se terminer plus tôt, elle se terminera plus tôt. CPU vous remercie tous directement.

En fait, il y a quelque chose qui peut être optimisé ici, c'est-à-dire que la longueur de notre tableau peut être extraite sans avoir à y accéder à chaque fois, c'est-à-dire :

function findUserByName(users) {
    let length = users.length
    for (let i = 0; i < length; i++) {
        if (users[i].name === '章三') return users[i]
    }
}


Cela peut sembler un peu compliqué, et c'est le cas, mais si l'on considère les performances, cela reste utile. Par exemple, la fonction size() de certaines collections n'est pas un simple accès aux attributs, mais doit être calculée une fois à chaque fois. Ce scénario est une grande optimisation, car il enregistre le processus de nombreux appels de fonction, ce qui signifie qu'il existe de nombreuses économies. instructions d'appel et de retour, ce qui améliore simplement l'efficacité du code. Surtout dans le cas d'énoncés en boucle où les changements quantitatifs conduisent facilement à des changements qualitatifs, l'écart se creuse à partir de ce détail.

Référence du processus d'appel de fonction :

appel de fonction

Le code correspondant est le suivant :

let a = 10
let b = 11

function sum (a, b) {
    return a + b
}


Après avoir parlé de quelques affirmations de base, jetons un coup d’œil au cadre que nous utilisons souvent. Les performances dans de nombreux endroits méritent d’être explorées.

algorithme de comparaison

Vue et React utilisent tous deux le DOM virtuel. Lors des mises à jour, comparez l'ancien et le nouveau DOM virtuel. Sans aucune optimisation, la complexité temporelle de la différence directe et stricte de deux arbres est O(n^3), ce qui n'est pas du tout utilisable. Par conséquent, Vue et React doivent utiliser l'algorithme diff pour optimiser le DOM virtuel :

Vue2 - Comparaison double :

Vue2 - Comparaison double

Similaire à l'image ci-dessus :

  • Définir 4 variables : oldStartIdx, oldEndIdx, newStartIdx et newEndIdx

  • Déterminer si oldStartIdx et newStartIdx sont égaux

  • Déterminer si oldEndIdx et newEndIdx sont égaux

  • Déterminer si oldStartIdx et newEndIdx sont égaux

  • Déterminer si oldEndIdx et newStartIdx sont égaux

  • En même temps, oldStartIdx et newStartIdx se déplacent vers la droite ; oldEndIdx et newEndIdx se déplacent vers la gauche.

Vue3 - Sous-séquence croissante la plus longue :

Vue3 - sous-séquence croissante la plus longue

L'ensemble du processus est à nouveau optimisé sur la base de la comparaison double de Vue2. Par exemple, la capture d'écran ci-dessus :

  • Effectuez d'abord une comparaison à double extrémité et constatez que les deux premiers nœuds (A et B) et le dernier nœud (G) sont identiques et n'ont pas besoin d'être déplacés.

  • Trouvez la sous-séquence croissante la plus longue C, D, E (un groupe de nœuds qui comprend à la fois les anciens et les nouveaux enfants, et l'ordre le plus long n'a pas changé)

  • Traitez la sous-séquence dans son ensemble, sans aucune opération interne, il suffit de déplacer F devant celle-ci et d'insérer H derrière.

Réagir - décaler vers la droite uniquement :

Réagir - décaler vers la droite uniquement

Le processus de comparaison de la capture d'écran ci-dessus est le suivant :

  • Parcourez Old et enregistrez la carte d'indice correspondante

  • En parcourant New, l'indice de b passe de 1 à 0 et ne bouge pas (c'est un décalage à gauche, pas un décalage à droite)

  • L'indice de c passe de 2 à 1, et ne bouge pas (il se déplace aussi vers la gauche, pas vers la droite)

  • L'indice de a passe de 0 à 2, en se déplaçant vers la droite, et les indices de b et c sont réduits de 1.

  • Les positions de d et e n'ont pas changé et n'ont pas besoin d'être déplacées.

En bref, quel que soit l’algorithme utilisé, leurs principes sont les suivants :

  • Comparez uniquement au même niveau, pas entre les niveaux

  • Si le Tag est différent, supprimez-le et reconstruisez-le (ne comparez plus les détails internes)

  • Les nœuds enfants se distinguent par clé (importance de la clé)

En fin de compte, la complexité temporelle a été réduite à O(n) avant de pouvoir être utilisée dans nos projets réels.

SetState est-il vraiment asynchrone ?

Beaucoup de gens pensent que setState est asynchrone, mais regardez l'exemple suivant :

clickHandler = () => {
    console.log('--- start ---')

    Promise.resolve().then(() => console.log('promise then'))

    this.setState({val: 1}, () => {console.log('state...', this.state.val)})

    console.log('--- end ---')
}

render() {
    return <div onClick={this.clickHandler}>setState</div>
}


Résultat d'impression réel :

résultats d'impression setState

S'il est asynchrone, l'impression de l'état doit être exécutée après la promesse de la microtâche.

Afin d'expliquer cette raison, nous devons d'abord comprendre le mécanisme des événements dans JSX.

Les événements dans JSX, tels que onClick={() => {}}, sont en fait appelés événements synthétiques, qui sont différents des événements personnalisés que nous appelons souvent :

// 自定义事件
document.getElementById('app').addEventListener('click', () => {})


Les événements synthétiques sont liés au nœud racine et ont des pré- et post-opérations. Prenons l'exemple ci-dessus :

function fn() { // fn 是合成事件函数,内部事件同步执行
    // 前置
    clickHandler()
    
    // 后置,执行 setState 的 callback
}


Vous pouvez imaginer qu'il existe une fonction fn et que les événements qu'elle contient sont exécutés de manière synchrone, y compris setState. Une fois fn exécuté, l'événement asynchrone commence à être exécuté, c'est-à-dire Promise.then, ce qui est cohérent avec le résultat imprimé.

Alors pourquoi React fait-il cela ?
Pour des raisons de performances, si l'état doit être modifié plusieurs fois, React fusionnera d'abord ces modifications et ne restituera le DOM qu'une seule fois après la fusion pour éviter de restituer le DOM à chaque fois qu'il est modifié.

Par conséquent, setState est de nature synchrone, et "asynchrone" dont nous parlons habituellement n'est pas rigoureux.

Algorithme frontal

Après avoir parlé de notre développement quotidien, parlons de l’application des algorithmes dans le front-end.

Rappel amical : les algorithmes sont généralement conçus pour de gros volumes de données, ce qui est différent du développement quotidien.

Si vous pouvez utiliser des types valeur, vous n’avez pas besoin de types référence.

Examinons d’abord une question.

Trouvez tous les nombres symétriques compris entre 1 et 10 000, par exemple : 0, 1, 2, 11, 22, 101, 232, 1221...

Idée 1 - Utiliser l'inversion et la comparaison de tableaux : convertissez les nombres en chaînes, puis convertissez-les en tableaux ; inversez les tableaux, puis joignez-les en chaînes ; comparez les chaînes avant et après.

function findPalindromeNumbers1(max) {
    const res = []
    if (max <= 0) return res

    for (let i = 1; i <= max; i++) {
        // 转换为字符串,转换为数组,再反转,比较
        const s = i.toString()
        if (s === s.split('').reverse().join('')) {
            res.push(i)
        }
    }

    return res
}


Idée 2 – Comparaison du début et de la fin d’une chaîne : convertissez les nombres en chaînes ; comparez les caractères de début et de fin d’une chaîne.

function findPalindromeNumbers2(max) {
    const res = []
    if (max <= 0) return res

    for (let i = 1; i <= max; i++) {
        const s = i.toString()
        const length = s.length

        // 字符串头尾比较
        let flag = true
        let startIndex = 0 // 字符串开始
        let endIndex = length - 1 // 字符串结束
        while (startIndex < endIndex) {
            if (s[startIndex] !== s[endIndex]) {
                flag = false
                break
            } else {
                // 继续比较
                startIndex++
                endIndex--
            }
        }

        if (flag) res.push(res)
    }

    return res
}


Idée 3 - Générer des numéros inversés : utilisez % et Math.floor pour générer des numéros inversés ; comparez les nombres avant et après (numéros opérationnels partout, pas de type de chaîne).

function findPalindromeNumbers3(max) {
    const res = []
    if (max <= 0) return res

    for (let i = 1; i <= max; i++) {
        let n = i
        let rev = 0 // 存储翻转数

        // 生成翻转数
        while (n > 0) {
            rev = rev * 10 + n % 10
            n = Math.floor(n / 10)
        }

        if (i === rev) res.push(i)
    }

    return res
}


Analyse des performances : aller plus vite

  • Idée 1- Cela semble être O(n), mais la conversion et le fonctionnement du tableau prennent du temps, donc c'est lent

  • Idée 2 VS Idée 3 - Manipuler les nombres plus rapidement (le prototype informatique est une calculatrice)

En bref, essayez de ne pas convertir les structures de données, en particulier les structures ordonnées telles que les tableaux, et essayez de ne pas utiliser d'API intégrées telles que reverse. Il est difficile d'identifier la complexité. Les opérations sur les nombres sont les plus rapides, suivies par les chaînes.

Essayez d'utiliser du code "de bas niveau"

Passons directement à la question suivante.

Entrez une chaîne et changez les lettres majuscules et minuscules.
Par exemple, saisissez la chaîne 12aBc34 et affichez la chaîne 12AbC34.

Idée 1 – Utilisez des expressions régulières.

function switchLetterCase(s) {
    let res = ''

    const length = s.length
    if (length === 0) return res

    const reg1 = /[a-z]
    const reg2 = /[A-Z]

    for (let i = 0; i < length; i++) {
        const c = s[i]
        if (reg1.test(c)) {
            res += c.toUpperCase()
        } else if (reg2.test(c)) {
            res += c.toLowerCase()
        } else {
            res += c
        }
    }

    return res
}


Idée 2 - Juger par le code ASCII.

function switchLetterCase2(s) {
    let res = ''

    const length = s.length
    if (length === 0) return res

    for (let i = 0; i < length; i++) {
        const c = s[i]
        const code = c.charCodeAt(0)

        if (code >= 65 && code <= 90) {
            res += c.toLowerCase()
        } else if (code >= 97 && code <= 122) {
            res += c.toUpperCase()
        } else {
            res += c
        }
    }

    return res
}


Analyse des performances : la première utilise la régularisation et est plus lente que la seconde

Par conséquent, essayez d’utiliser du code « de bas niveau » et utilisez le sucre syntaxique, les API de haut niveau ou les expressions régulières avec prudence.

Couche inférieure de l'ordinateur

Enfin, parlons de certains des aspects sous-jacents de l’ordinateur que le front-end doit comprendre.

Lire les données de la "mémoire"

Ce que nous disons habituellement : lire des données de la mémoire signifie lire des données dans des registres. Cependant, nos données ne sont pas lues directement de la mémoire dans les registres, mais sont d'abord lues dans un cache, puis lues dans les registres.

Le registre se trouve dans le CPU et fait également partie du CPU, de sorte que le CPU lit et écrit très rapidement les données du registre.

Pourquoi est-ce? Parce que la lecture des données de la mémoire est trop lente.

Vous pouvez le comprendre de cette façon : le processeur lit d'abord les données dans le cache pour les utiliser, et lorsqu'elles sont réellement utilisées, il lit le registre dans le cache ; lorsque le registre est utilisé, il réécrit les données dans le cache, et puis le cache écrit ensuite les données dans la mémoire au moment approprié.

La vitesse de fonctionnement du processeur est très rapide, mais la lecture des données de la mémoire est très lente. Si vous lisez et écrivez des données de la mémoire à chaque fois, cela ralentira inévitablement la vitesse de fonctionnement du processeur. L'exécution peut prendre 100 secondes et 99 secondes. des secondes seront consacrées à la lecture des données. Afin de résoudre ce problème, nous mettons un cache entre le CPU et la mémoire, et la vitesse de lecture et d'écriture entre le CPU et le cache est très rapide. Le CPU lit et écrit uniquement des données vers et depuis le cache, quel que soit le cache et le cache.Comment synchroniser les données entre les mémoires. Cela résout le problème de la lecture et de l’écriture lentes de la mémoire.

Opérations sur les bits binaires

Une utilisation flexible des opérations sur bits binaires peut non seulement augmenter la vitesse, mais une utilisation compétente du binaire peut également économiser de la mémoire.

Si un nombre n est donné, comment déterminer si n est 2 élevé à la puissance n ?

C'est très simple, il suffit de demander le reste.

function isPowerOfTwo(n) {
    if (n <= 0) return false
    let temp = n
    while (temp > 1) {
        if (temp % 2 != 0) return false
        temp /= 2
    }
    return true
}


Eh bien, il n’y a rien de mal avec le code, mais ce n’est pas assez bon. Jetez un œil au code ci-dessous :

function isPowerOfTwo(n) {
    return (n > 0) && ((n & (n - 1)) == 0)
}


Vous pouvez utiliser console.time et console.timeEnd pour comparer la vitesse d'exécution.

Nous pouvons également constater qu'il existe de nombreuses variables d'indicateur dans certains codes sources. Nous effectuons des opérations ET au niveau du bit ou OU au niveau du bit sur ces indicateurs pour détecter les indicateurs et déterminer si une certaine fonction est activée. Pourquoi n'utilise-t-il pas simplement des valeurs booléennes ? C'est très simple, c'est efficace et économise de la mémoire.

Par exemple, ce code dans le code source de Vue3 utilise non seulement AND au niveau du bit et OR au niveau du bit, mais utilise également le décalage vers la gauche :

export const enum ShapeFlags {
  ELEMENT = 1,
  FUNCTIONAL_COMPONENT = 1 << 1,
  STATEFUL_COMPONENT = 1 << 2,
  TEXT_CHILDREN = 1 << 3,
  ARRAY_CHILDREN = 1 << 4,
  SLOTS_CHILDREN = 1 << 5,
  TELEPORT = 1 << 6,
  SUSPENSE = 1 << 7,
  COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
  COMPONENT_KEPT_ALIVE = 1 << 9,
  COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
}


if (shapeFlag & ShapeFlags.ELEMENT || shapeFlag & ShapeFlags.TELEPORT) {
  ...
}


if (hasDynamicKeys) {
      patchFlag |= PatchFlags.FULL_PROPS
    } else {
    if (hasClassBinding) {
      patchFlag |= PatchFlags.CLASS
    }
    if (hasStyleBinding) {
      patchFlag |= PatchFlags.STYLE
    }
    if (dynamicPropNames.length) {
      patchFlag |= PatchFlags.PROPS
    }
    if (hasHydrationEventBinding) {
      patchFlag |= PatchFlags.HYDRATE_EVENTS
    }
}


Conclusion

L'article explique les performances du front-end au niveau du code, avec des dimensions approfondies :

  • Analyse approfondie des connaissances de base de JS

  • Code source du cadre

Il existe également des dimensions de largeur :

  • Animations CSS, composants

  • algorithme

  • Couche inférieure de l'ordinateur

J'espère que cela pourra aider tout le monde à élargir ses horizons en matière de performances front-end. Si vous êtes intéressé par l'article, veuillez laisser un message pour discussion ~~~

Auteur : JD Retail Yang Jinjun

Source : Communauté de développeurs JD Cloud Veuillez indiquer la source lors de la réimpression

Amende de 200 yuans et plus d'un million de yuans confisqués You Yuxi : L'importance des documents chinois de haute qualité La migration massive des serveurs de Musk Le contrôle de la congestion TCP a sauvé Internet Apache OpenOffice est un projet de facto « non maintenu » Google fête son 25e anniversaire Microsoft open source windows-drivers-rs, utilisez Rust pour développer des pilotes Windows Raspberry Pi 5 sera publié fin octobre, au prix de 60 $ Conteneurs macOS : utilisez Docker pour exécuter des images macOS sur macOS IntelliJ IDEA 2023.3 EAP publié
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/u/4090830/blog/10114289
conseillé
Classement