文档章节

编写高性能的 JavaScript:

duozuo2006
 duozuo2006
发布于 2016/12/06 01:02
字数 1318
阅读 3
收藏 0
点赞 0
评论 0

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

Monomorphism:单态性

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

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

 

Constants:常量

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

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:内联

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 fast

if (entity.type === E_TYPE.Robot) {

  

}

 

// perfect

// right side of binary expression can even get unfold

if (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

}

 

// 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

尽可能避免使用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' now

vec2.z = 0;

 

// good, compiler knows this member

vec2.x = 1;

 

Loops

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

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

// 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

);

© 著作权归作者所有

共有 人打赏支持
duozuo2006
粉丝 0
博文 10
码字总数 8728
作品 0
北京
JavaScript 如何打败众语言,成为 Node 的实现语言?

Node.js 是一种将 JS 放在服务器端实现的平台,而为什么要把js放到服务器端实现,JS 最初设计是在浏览器端解释执行,后来为什么搞Node.js 把他放在服务器端执行呢? 关于这个问题,近日有网友...

达尔文 ⋅ 04/21 ⋅ 0

python_day14_前端_JS-重写

说明 ECMA(欧洲计算机制造协会)   ECMA(欧洲计算机制造协会)定义了ECMA-262规范.国际标准化组织及国际电工委员会(ISO/IEC)也采纳 ECMAScript 作为标准(ISO/IEC-16262)。从此,Web 浏览...

812374156 ⋅ 05/25 ⋅ 0

JVM 即时编译器 - GraalVM

Graal — 新的 JVM 即时编译器 GraalVM 是新一代的高性能跨语言虚拟机,用于运行 JavaScript、Python 3、Ruby、R、基于 JVM 的语言,如 Java、Scala、Kotlin 和基于 LLVM 的语言,如 C 和 C+...

匿名 ⋅ 2014/09/29 ⋅ 2

JavaWeb01-HTML篇笔记(七)

.1 案例三:完成对注册页面的数据的简单校验.1.1.1 需求: 对注册页面的数据进行非空的简单校验!!!如果有某个值没有输入,点击提交,弹出一个对话框进行提示!! 1.1.2 分析:1.1.2.1 技术分...

我是小谷粒 ⋅ 04/28 ⋅ 0

Chrome V8 与 Node.js

从某种意义上来说,Node.js 并不是一个从零开始编写的 JavaScript 运行时,它其实也是站在“巨人的肩膀”上进行了一系列的拼凑和封装得到的结果。它的高效离不开一些很牛的第三方程序和类库。...

博文视点 ⋅ 06/14 ⋅ 0

JavaScript 工作原理之六-WebAssembly 对比 JavaScript 及其使用场景

原文请查阅这里,略有改动,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland。 本系列持续更新中,Github 地址请查阅这里。 这是 JavaScript 工作原理的第六章。 现在,我们将会剖析...

tristan ⋅ 05/15 ⋅ 0

Lynx技术分析-JS引擎扩展设计

JS Binding 技术 Lynx(一个高效的跨平台框架) 的 JS Binding 技术最主要的目的是搭建一个高效的与 JS 引擎解耦的通信桥梁,同时具备 JS 引擎切换的能力。该技术经历了多次迭代,最终通过抽...

hxxft ⋅ 05/15 ⋅ 0

JavaScript 和服务器端方向推荐书单(附简评)

我一直以来读书是获取知识最好的方式,很长时间以来,我都在博客维护了一个 推荐书单,最近又做了一些整理,为每本书都添加了简评,希望能对大家有帮助,当然如果能用我的推广链接购书就再好...

eapxuo ⋅ 02/09 ⋅ 0

Excel 开始支持使用 JavaScript 编写自定义函数

0. 概述 微软为 Excel 增加了使用 JavaScript 编写自定义函数的支持。 1. 示例 比如一个功能:两数之和加 : 我们可以使用 JavaScript 编写: 然后就像使用其它 Excel 内置函数一样,这样调用...

justjavac ⋅ 05/09 ⋅ 0

用于学习编程和 AI 的教学游戏 - WarriorJS

WarriorJS 是一个采用 JavaScript 开发的教学类游戏,用于学习 JavaScript 编程和人工智能。 简单地说,WarriorJS 是一个需要靠编写 JS 来玩的小游戏,启动后你需要不断攀爬 JS 世界,最终爬...

匿名 ⋅ 2015/05/26 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

懒惰根本就不存在

简评:芝加哥大学心理学教授,懒惰根本就不存在。(本文表面讲行为心理学实则讲教育) 金句:以好奇而不是判断来回应一个人的无效行为,是非常有帮助的。 本文「我」代表原作者 E Price。 自...

极光推送 ⋅ 23分钟前 ⋅ 0

Excel提取单元格中最后一个“.”后面的数据

java.lang.String ----- String =TRIM((MID(SUBSTITUTE(B2,".",REPT(" ",99)),(LEN(B2)-LEN(SUBSTITUTE(B2,".","")))*99,99)))...

klog ⋅ 25分钟前 ⋅ 0

mac远程桌面

下载安装remote-desktop-mac Mac beta 客户端 mac通过远程桌面访问windows服务器。

亚林瓜子 ⋅ 29分钟前 ⋅ 0

firrtl

动手---sbt(2)之后,再回头看 chisel第一个实验,根据 https://github.com/freechipsproject/firrtl 发现firrtl没有执行sbt assembly命令,重新执行这个命令,结果成功。如下图: joe@joe-As...

whoisliang ⋅ 33分钟前 ⋅ 0

NIO

一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。 二、通道的主要实现类 java.nio.channel...

stars永恒 ⋅ 34分钟前 ⋅ 0

Android悬浮窗的实现

0. 前言   现在很多应用都使用到悬浮窗,例如微信在视频的时候,点击Home键,视频小窗口仍然会在屏幕上显示。这个功能在很多情况下都非常有用。那么今天我们就来实现一下Android悬浮窗,以...

猴亮屏 ⋅ 34分钟前 ⋅ 0

日志采集中的关键技术分析

概述 日志从最初面向人类演变到现在的面向机器发生了巨大的变化。最初的日志主要的消费者是软件工程师,他们通过读取日志来排查问题,如今,大量机器日夜处理日志数据以生成可读性的报告以此...

tqyin ⋅ 35分钟前 ⋅ 0

使用Navicat将数据导出为text文本 然后再导入

将数据导出为text文本效率很高 1. 准备工作 1.1 准备表结构 1.2 目标库 执行生成表结构sql 2.将表数据导出为text文本 生成的text文本 3. 目标库 导入text 4.效果...

Lucky_Me ⋅ 41分钟前 ⋅ 0

IntelliJ IDEA 乱码解决方案 (项目代码、控制台等)

文章介绍了idea下,项目乱码、控制台乱码及运行tomcat控制台乱码的解决方案,文章链接:https://www.cnblogs.com/vhua/p/idea_1.html

Funcy1122 ⋅ 44分钟前 ⋅ 0

IDEA使用sonarLint

一、IDEA如何安装SonarLint插件 1.打开 Idea 2.点击【File】 3.点击【Settings】 4.点击【Plugins】 5.在搜索栏中输入“sonarlint”关键字 6.点击【Install】进行安装 7.重启Idea 二、IDEA如...

开源中国成都区源花 ⋅ 49分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部