博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2016:编写高性能的JavaScript
阅读量:6988 次
发布时间:2019-06-27

本文共 3785 字,大约阅读时间需要 12 分钟。

翻译自Felix Maier的文章。本文从属于笔者的中系列文章。

本文的初衷是想介绍如何利用些简单的代码小技巧就能促进JavaScript编译器的优化进程从而提升代码运行效率。特别是在游戏这种对于垃圾回收速度要求较高,你性能稍微差点用户就能见到白屏的地方。

Monomorphism:单态性

JavaScript中允许函数调用时候传入动态参数,不过就以简单的2参数函数为例,当你的参数类型、参数数目与返回类型动态调用时才能决定,编译器需要更多的时间来解析。编译器自然地希望能够处理那些单态可预测的数据结构、参数统计等。

function example(a, b) {  // we expect a, b to be numeric  console.log(++a * ++b);};example(); // badexample(1); // still badexample("1", 2); // dammit megexample(1, 2); // good

Constants:常量

使用常量能够让编译器在编译时即完成变量的值替换:

const a = 42; // we can easily unfold thisconst b = 1337 * 2; // we can resolve this expressionconst c = a + b; // still can be resolvedconst d = Math.random() * c; // we can only unfold 'c'// before unfoldinga;b;c;d;// after unfolding// we can do this at compile time!42;2674;2716;Math.random() * 2716;

Inlining:内联

JIT编译器能够找出你的代码中被执行次数最多的部分,将你的代码分割成多个小的代码块能够有助于编译器在编译时将这些代码块转化为内联格式然后增加执行速度。

Data Types:数据类型

尽可能地多用Numbers与Booleans类型,因为他们与其他类似于字符串等原始类型相比性能表现更好。使用字符串类型可能会带来额外的垃圾回收消耗。

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 fastif (entity.type === E_TYPE.Robot) {  }// perfect// right side of binary expression can even get unfoldif (entity.type === ROBOT) {  }

Strict & Abstract Operators

尽可能使用===这个严格比较操作符而不是==操作符。使用严格比较操作符能够避免编译器进行类型推导与转换,从而提高一定的性能。

Strict Conditions

JavaScript中的if语句也非常灵活,你可以直接在if(a) then bla这个类型的条件选择语句中传入随意类似的a值。不过这种情况下,就像上文提及的严格比较操作符与宽松比较操作符一样,编译器需要将其转化为多个数据类型进行比较,而不能立刻得出结果。当然,这并不是一味的反对使用简写方式,而是在非常强调性能的场景,还是建议做好每一个细节的优化:

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 }// goodif (a === 2) {  // do sth }// same goes for functionsfunction 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

尽可能避免使用arguments[index]方式进行参数获取,并且尽量避免修改传入的参数变量:

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'};

Toxicity:这些关键字有毒

Toxicity

如下列举的几个语法特性会影响优化进程:

  • eval

  • with

  • try/catch

同时尽量避免在函数内声明函数或者闭包,可能在大量的运算中导致过多的垃圾回收操作。

Objecs

Object实例通常会共享隐类,因此当我们访问或者设置某个实例的未预定义变量值的时候会创建一个隐类。

// 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' nowvec2.z = 0;// good, compiler knows this membervec2.x = 1;

Loops

尽可能的缓存数组长度的计算值,并且尽可能在同一个数组中存放单个类型。避免使用for-in语法来遍历某个数组,因为它真的很慢。另外,continue与break语句在循环中的性能也是不错的,这一点使用的时候不用担心。另外,尽可能将短小的逻辑部分拆分到独立的函数中,这样更有利于编译器进行优化。另外,使用前缀自增表达式,也能带来小小的性能提升。(++i代替i++)

let badarray = [1, true, 0]; // bad, dont mix typeslet array = [1, 0, 1]; // happy compiler// bad choicefor (let key in array) {  };// better// but always try to cache the array sizelet i = 0;for (; i < array.length; ++i) {  key = array[i];};// goodlet i = 0;let key = null;let length = array.length;for (; i < length; ++i) {  key = array[i];};

drawImage

draeImage函数算是最快的2D Canvas API之一了,不过我们需要注意的是如果为了图方便省略了全参数传入,也会增加性能损耗:

// badctx.drawImage(  img,  x, y);// goodctx.drawImage(  img,  // clipping  sx, sy,  sw, sh,  // actual stuff  x, y,  w, h);// much hax// no subpixel rendering by passing integersctx.drawImage(  img,  sx|0, sy|0,  sw|0, sh|0,  x|0, y|0,  w|0, h|0);

转载地址:http://ynzvl.baihongyu.com/

你可能感兴趣的文章
Drools
查看>>
MYSQL create database 和 create table 做了一些什么!
查看>>
index_ss hint 使用的运行计划变化对照
查看>>
【经典面试题】实现平方根函数sqrt
查看>>
OSI七层模型具体解释
查看>>
cocos2dx触屏响应(单点触摸)CCTouchBegan,CCTouchMove,CCTouchEnd
查看>>
《古都》--[日]川端康成
查看>>
xcache 安装配置
查看>>
OCP开放封闭原则
查看>>
瀑布流布局
查看>>
福施福、爱乐维、玛特纳各成分比较(已换算成同一单位)
查看>>
windows 7 SDK和DDK下载地址
查看>>
智力测试
查看>>
javascript技术难点(三)之this、new、apply和call详解
查看>>
Javascript中Array.prototype.map()详解
查看>>
android scrollview 实现上下左右滚动方法
查看>>
Fourth glance in Go
查看>>
servlet&jsp高级:第二部分
查看>>
自拉ADSL网线搭建站点server,解决动态IP、无公网IP、80port被封、HTTP被屏蔽的方法...
查看>>
常用 CSS 中文字体 Unicode 编码表
查看>>