Maison >interface Web >js tutoriel >Écrire du JavaScript hautes performances

Écrire du JavaScript hautes performances

黄舟
黄舟original
2017-02-21 11:45:441579parcourir



Écrire du JavaScript hautes performances

L'intention initiale de cet article est de présenter comment utiliser quelques astuces de codage simples pour améliorer le JavaScript. compilateur Le processus d'optimisation améliore l'efficacité de l'exécution du code. Surtout dans les jeux où la vitesse de récupération de place est élevée, les utilisateurs verront un écran blanc si les performances sont légèrement médiocres.

Monomorphisme : Monomorphisme

JavaScript permet de transmettre des paramètres dynamiques lors de l'appel de fonctions, mais en prenant une simple fonction à 2 paramètres comme exemple, lorsque votre type de paramètre, le nombre de paramètres et le type de retour Il ne peut être déterminé que lorsqu'il est appelé dynamiquement, et le compilateur a besoin de plus de temps pour l'analyser. Les compilateurs veulent naturellement être capables de gérer des structures de données monomorphiquement prévisibles, des statistiques de paramètres, etc.

function example(a, b) {
  // we expect a, b to be numeric
  console.log(++a * ++b);
};

example(); // bad
example(1); // still bad
example("1", 2); // dammit meg

example(1, 2); // good

Constantes : Constantes

L'utilisation de constantes permet au compilateur d'effectuer le remplacement de la valeur de la variable lors de la compilation :

const a = 42; // we can easily unfold this
const b = 1337 * 2; // we can resolve this expression
const c = a + b; // still can be resolved
const d = Math.random() * c; // we can only unfold 'c'

// before unfolding
a;
b;
c;
d;

// after unfolding
// we can do this at compile time!
42;
2674;
2716;
Math.random() * 2716;

Inlining : inlining

Le Le compilateur JIT peut trouver les parties les plus exécutées de votre code. Le fractionnement de votre code en plusieurs petits blocs de code peut aider le compilateur à convertir ces blocs de code au format en ligne au moment de la compilation.

Types de données : types de données

Utilisez autant que possible les nombres et les booléens car ils fonctionnent mieux que les autres types primitifs tels que les chaînes. L’utilisation de types de chaîne peut entraîner des coûts supplémentaires de récupération de place.

const ROBOT = 0;
const HUMAN = 1;
const SPIDER = 2;

let E_TYPE = {
  Robot: ROBOT,
  Human: HUMAN,
  Spider: SPIDER
};

// bad
// avoid uncached strings in heavy tasks (or better in general)
if (entity.type === "Robot") {
  
}

// good
// the compiler can resolve member expressions
// without much deepness pretty fast
if (entity.type === E_TYPE.Robot) {
  
}

// perfect
// right side of binary expression can even get unfold
if (entity.type === ROBOT) {
  
}

Opérateurs stricts et abstraits

Utilisez l'opérateur de comparaison strict === au lieu de l'opérateur == autant que possible. L'utilisation d'opérateurs de comparaison stricts peut éviter au compilateur d'effectuer une déduction et une conversion de type, améliorant ainsi certaines performances.

Conditions strictes

L'instruction if en JavaScript est également très flexible. Vous pouvez directement transmettre n'importe quelle valeur similaire dans une instruction de sélection conditionnelle du type if(a) then bla. Cependant, dans ce cas, tout comme les opérateurs de comparaison stricts et les opérateurs de comparaison lâches mentionnés ci-dessus, le compilateur doit les convertir en plusieurs types de données à des fins de comparaison, et les résultats ne peuvent pas être obtenus immédiatement. Bien sûr, il ne s'agit pas de s'opposer aveuglément à l'utilisation d'abréviations, mais dans les scénarios qui mettent beaucoup l'accent sur les performances, il est recommandé d'optimiser chaque détail :

let a = 2;

// bad
// abstracts to check in the worst case:
// - is value equal to true
// - is value greater than zero
// - is value not null
// - is value not NaN
// ..
if (a) {
 // if a is true, do something 
}

// good
if (a === 2) {
  // do sth 
}

// same goes for functions
function b() {
  return (!false);
};

if (b()) {
  // get in here slow
}

if (b() === true) {
  // get in here fast
  // the compiler knows a specific value to compare with
}

Arguments

Éviter comme autant que possible Utilisez la méthode arguments[index] pour obtenir les paramètres, et essayez d'éviter de modifier les variables de paramètre passées :

function mul(a, b) {
  return (arguments[0]*arguments[1]); // bad, very slow
  return (a*b); // good
};

function test(a, b) {
  a = 5; // bad, dont modify argument identifiers
  let tmp = a; // good
  tmp *= 2; // we can now modify our fake 'a'
};

Toxicité : Ces mots-clés sont toxiques

Toxicité

sont répertoriés ci-dessous Plusieurs caractéristiques grammaticales affecteront le processus d'optimisation :

  • eval

  • avec

  • try/ catch

En même temps, essayez d'éviter de déclarer des fonctions ou des fermetures à l'intérieur des fonctions, ce qui pourrait entraîner trop d'opérations de garbage collection dans un grand nombre d'opérations.

Objecs

Les instances d'objet partagent généralement des classes implicites, donc lorsque nous accédons ou définissons la valeur d'une variable non définie d'une instance, une classe implicite est créée.

// our hidden class 'hc_0'
class Vector {
  constructor(x, y) {
    // compiler finds and expects member declarations here
    this.x = x;
    this.y = y;
  }
};

// both vector objects share hidden class 'hc_0'
let vec1 = new Vector(0, 0);
let vec2 = new Vector(2, 2);

// bad, vec2 got hidden class 'hc_1' now
vec2.z = 0;

// good, compiler knows this member
vec2.x = 1;

Boucles

Mettez en cache autant que possible la valeur calculée de la longueur du tableau et stockez autant que possible un seul type dans le même tableau. Évitez d'utiliser la syntaxe for-in pour parcourir un tableau car elle est très lente. De plus, les performances des instructions continue et break dans les boucles sont également bonnes, vous n'avez donc pas à vous en soucier lorsque vous les utilisez. De plus, divisez autant que possible les parties logiques courtes en fonctions indépendantes, ce qui est plus propice à l'optimisation du compilateur. De plus, l’utilisation d’expressions d’incrémentation automatique de préfixe peut également apporter de légères améliorations de performances. (je remplace i) La fonction

let badarray = [1, true, 0]; // bad, dont mix types
let array = [1, 0, 1]; // happy compiler

// bad choice
for (let key in array) {
  
};

// better
// but always try to cache the array size
let i = 0;
for (; i < array.length; ++i) {
  key = array[i];
};

// good
let i = 0;
let key = null;
let length = array.length;
for (; i < length; ++i) {
  key = array[i];
};

drawImage

draeImage est l'une des API Canvas 2D les plus rapides, mais nous devons faire attention si tous les paramètres sont omis pour des raisons de commodité. , augmentera également la perte de performances :

// bad
ctx.drawImage(
  img,
  x, y
);

// good
ctx.drawImage(
  img,
  // clipping
  sx, sy,
  sw, sh,
  // actual stuff
  x, y,
  w, h
);

// much hax
// no subpixel rendering by passing integers
ctx.drawImage(
  img,
  sx|0, sy|0,
  sw|0, sh|0,
  x|0, y|0,
  w|0, h|0
);

Ce qui précède est le contenu de l'écriture de JavaScript hautes performances. Pour plus de contenu connexe, veuillez prêter attention au site Web PHP chinois (www. php.cn) !


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn