[翻译]High Performance JavaScript(026)

来源:互联网 发布:壳域名仅限局域网使用 编辑:程序博客网 时间:2024/06/05 19:36

Use the Fast Parts  使用速度快的部分

 

    Even though JavaScript is often blamed for being slow, there are parts of the language that are incredibly fast. This should come as no surprise, since JavaScript engines are built in lower-level languages and are therefore compiled. Though it's easy to blame the engine when JavaScript appears slow, the engine is typically the fastest part of the process; it's your code that is actually running slowly. There are parts of the engine that are much faster than others because they allow you to bypass the slow parts.

    虽然JavaScript经常被指责缓慢,然而此语言的某些部分具有难以置信的快速。这不足为奇因为JavaScript引擎由低级语言构建。虽然JavaScript速度慢很容易被归咎于引擎,然而引擎通常是处理过程中最快的部分,实际上速度慢的是你的代码。引擎的某些部分比其它部分快很多,因为它们允许你绕过速度慢的部分。

 

Bitwise Operators  位操作运算符

 

    Bitwise operators are one of the most frequently misunderstood aspects of JavaScript. General opinion is that developers don't understand how to use these operators and frequently mistake them for their Boolean equivalents. As a result, bitwise operators are used infrequently in JavaScript development, despite their advantages.

    位操作运算符是JavaScript中经常被误解的内容之一。一般的看法是,开发者不知道如何使用这些操作符,经常在布尔表达式中误用。结果导致JavaScript开发中不常用位操作运算符,尽管它们具有优势。

 

    JavaScript numbers are all stored in IEEE-754 64-bit format. For bitwise operations, though, the number is converted into a signed 32-bit representation. Each operator then works directly on this 32-bit representation to achieve a result. Despite the conversion, this process is incredibly fast when compared to other mathematical and Boolean operations in JavaScript.

    JavaScript中的数字按照IEEE-754标准64位格式存储。在位运算中,数字被转换为有符号32位格式。每种操作均直接操作在这个32位数上实现结果。尽管需要转换,这个过程与JavaScript中其他数学和布尔运算相比还是非常快。

 

    If you're unfamiliar with binary representation of numbers, JavaScript makes it easy to convert a number into a string containing its binary equivalent by using the toString() method and passing in the number 2. For example:

    如果你对数字的二进制表示法不熟悉,JavaScript可以很容易地将数字转换为字符串形式的二进制表达式,通过使用toString()方法并传入数字2(做参数)。例如:

 

var num1 = 25,
num2 = 3;
alert(num1.toString(2)); //"11001"
alert(num2.toString(2));
// "11"

    Note that this representation omits the leading zeros of a number.

    请注意,该表达式消隐了数字高位的零。

 

    There are four bitwise logic operators in JavaScript:

    JavaScript中有四种位逻辑操作符:

 

Bitwise AND  位与
    Returns a number with a 1 in each bit where both numbers have a 1

    两个操作数的位都是1,结果才是1

 

Bitwise OR  位或
    Returns a number with a 1 in each bit where either number has a 1

    有一个操作数的位是1,结果就是1

 

Bitwise XOR  位异或
    Returns a number with a 1 in each bit where exactly one number has a 1

    两个位中只有一个1,结果才是1

 

Bitwise NOT  位非
    Returns 1 in each position where the number has a 0 and vice versa

    遇0返回1,反之亦然

 

    These operators are used as follows:

    这些操作符用法如下:

 

//bitwise AND
var result1 = 25 & 3; //1
alert(result.toString(2)); //"1"
//bitwise OR
var result2 = 25 | 3; //27
alert(resul2.toString(2)); //"11011"
//bitwise XOR
var result3 = 25 ^ 3; //26
alert(resul3.toString(2)); //"11000"
//bitwise NOT
var result = ~25; //-26
alert(resul2.toString(2));
//"-11010"

    There are a couple of ways to use bitwise operators to speed up your JavaScript. The first is to use bitwise operations instead of pure mathematical operations. For example, it's common to alternate table row colors by calculating the modulus of 2 for a given number, such as:

    有许多方法可以使用位运算符提高JavaScript的速度。首先可以用位运算符替代纯数学操作。例如,通常采用对2取模运算实现表行颜色交替显示,例如:

 

for (var i=0, len=rows.length; i < len; i++){
  if (i % 2) {
    className = "even";
  } else {
    className = "odd";
  }
  //apply class
}

    Calculating mod 2 requires the number to be divided by 2 to determine the remainder. If you were to look at the underlying 32-bit representation of numbers, a number is even if its first bit is 0 and is odd if its first bit is 1. This can easily be determined by using a bitwise AND operation on a given number and the number 1. When the number is even, the result of bitwise AND 1 is 0; when the number is odd, the result of bitwise AND 1 is 1. That means the previous code can be rewritten as follows:

    计算对2取模,需要用这个数除以2然后查看余数。如果你看到32位数字的底层(二进制)表示法,你会发现偶数的最低位是0,奇数的最低位是1。如果此数为偶数,那么它和1进行位与操作的结果就是0;如果此数为奇数,那么它和1进行位与操作的结果就是1。也就是说上面的代码可以重写如下:

 

for (var i=0, len=rows.length; i < len; i++){
  if (i & 1) {
    className = "odd";
  } else {
    className = "even";
  }
  //apply class
}

    Although the code change is small, the bitwise AND version is up to 50% faster than the original (depending on the browser).

    虽然代码改动不大,但位与版本比原始版本快了50%(取决于浏览器)。

 

    The second way to use bitwise operators is a technique known as a bitmask. Bitmasking is a popular technique in computer science when there are a number of Boolean options that may be present at the same time. The idea is to use each bit of a single number to indicate whether or not the option is present, effectively turning the number into an array of Boolean flags. Each option is given a value equivalent to a power of 2 so that the mask works. For example:

    第二种使用位操作的技术称作位掩码。位掩码在计算机科学中是一种常用的技术,可同时判断多个布尔选项,快速地将数字转换为布尔标志数组。掩码中每个选项的值都等于2的幂。例如:

 

var OPTION_A = 1;
var OPTION_B = 2;
var OPTION_C = 4;
var OPTION_D = 8;
var OPTION_E = 16;

    With the options defined, you can create a single number that contains multiple settings using the bitwise OR operator:

    通过定义这些选项,你可以用位或操作创建一个数字来包含多个选项:

 

var options = OPTION_A | OPTION_C | OPTION_D;

    You can then check whether a given option is available by using the bitwise AND operator. The operation returns 0 if the option isn't set and 1 if the option is set:

    你可以使用位与操作检查一个给定的选项是否可用。如果该选项未设置则运算结果为0,如果设置了那么运算结果为1:

 

//is option A in the list?
if (options & OPTION_A){
  //do something
}
//is option B in the list?
if (options & OPTION_B){
  //do something
}

    Bitmask operations such as this are quite fast because, as mentioned previously, the work is happening at a lower level of the system. If there are a number of options that are being saved together and checked frequently, bitmasks can help to speed up the overall approach.

    像这样的位掩码操作非常快,正因为前面提到的原因,操作发生在系统底层。如果许多选项保存在一起并经常检查,位掩码有助于加快整体性能。

 

Native Methods  原生方法

 

    No matter how optimal your JavaScript code is, it will never be faster than the native methods provided by the JavaScript engine. The reason for this is simple: the native parts of JavaScript—those already present in the browser before you write a line of code—are all written in a lower-level language such as C++. That means these methods are compiled down to machine code as part of the browser and therefore don't have the same limitations as your JavaScript code.

    无论你怎样优化JavaScript代码,它永远不会比JavaScript引擎提供的原生方法更快。其原因十分简单:JavaScript的原生部分——在你写代码之前它们已经存在于浏览器之中了——都是用低级语言写的,诸如C++。这意味着这些方法被编译成机器码,作为浏览器的一部分,不像你的JavaScript代码那样有那么多限制。

 

    A common mistake of inexperienced JavaScript developers is to perform complex mathematical operations in code when there are better performing versions available on the built-in Math object. The Math object contains properties and methods designed to make mathematical operations easier. There are several mathematical constants available:

    经验不足的JavaScript开发者经常犯的一个错误是在代码中进行复杂的数学运算,而没有使用内置Math对象中那些性能更好的版本。Math对象包含专门设计的属性和方法,使数学运算更容易。这里是一些数学常数:

 


    Each of these values is precalculated, so there is no need for you to calculate them yourself. There are also methods to handle mathematical calculations:

    这里的每个数值都是预计算好的,所以你不需要自己来计算它们。还有一些处理数学运算的方法:

 


    Using these methods is faster than recreating the same functionality in JavaScript code. Whenever you need to perform complex mathematical calculations, look to the Math object first.

    使用这些函数比同样功能的JavaScript代码更快。当你需要进行复杂数学计算时,首先查看Math对象。

 

    Another example is the Selectors API, which allows querying of a DOM document using CSS selectors. CSS queries were implemented natively in JavaScript and truly popularized by the jQuery JavaScript library. The jQuery engine is widely considered the fastest engine for CSS querying, but it is still much slower than the native methods. The native querySelector() and querySelectorAll() methods complete their tasks, on average, in 10% of the time it takes for JavaScript-based CSS querying. Most JavaScript libraries have now moved to use the native functionality when available to speed up their overall performance.

    另一个例子是选择器API,可以像使用CSS选择器那样查询DOM文档。CSS查询被JavaScript原生实现并通过jQuery这个JavaScript库推广开来。jQuery引擎被认为是最快的CSS查询引擎,但是它仍比原生方法慢。原生的querySelector()和querySelectorAll()方法完成它们的任务时,平均只需要基于JavaScript的CSS查询10%的时间。大多数JavaScript库已经使用了原生函数以提高它们的整体性能。

 

    Always use native methods when available, especially for mathematical calculations and DOM operations. The more work that is done with compiled code, the faster your code becomes.

    当原生方法可用时,尽量使用它们,尤其是数学运算和DOM操作。用编译后的代码做越多的事情,你的代码就会越快。

 

Summary  总结

 

    JavaScript presents some unique performance challenges related to the way you organize your code. As web applications have become more advanced, containing more and more lines of JavaScript to function, some patterns and antipatterns have emerged. Some programming practices to keep in mind:

    JavaScript提出了一些独特的性能挑战,关系到你组织代码的方法。网页应用变得越来越高级,包含的JavaScript代码越来越多,出现了一些模式和反模式。请牢记以下编程经验:

 

• Avoid the double evaluation penalty by avoiding the use of eval() and the Function() constructor. Also, pass functions into setTimeout() and setInterval() instead of strings.

  通过避免使用eval()和Function()构造器避免二次评估。此外,给setTimeout()和setInterval()传递函数参数而不是字符串参数。

 

• Use object and array literals when creating new objects and arrays. They are created and initialized faster than nonliteral forms.

  创建新对象和数组时使用对象直接量和数组直接量。它们比非直接量形式创建和初始化更快。

 

• Avoid doing the same work repeatedly. Use lazy loading or conditional advance loading when browser-detection logic is necessary.

  避免重复进行相同工作。当需要检测浏览器时,使用延迟加载或条件预加载。

 

• When performing mathematical operations, consider using bitwise operators that work directly on the underlying representation of the number.

  当执行数学远算时,考虑使用位操作,它直接在数字底层进行操作。

 

• Native methods are always faster than anything you can write in JavaScript. Use native methods whenever available.

  原生方法总是比JavaScript写的东西要快。尽量使用原生方法。

 

    As with many of the techniques and approaches covered in this book, you will see the greatest performance gains when these optimizations are applied to code that is run frequently.

    本书涵盖了很多技术和方法,如果将这些优化应用在那些经常运行的代码上,你将会看到巨大的性能提升。

原创粉丝点击