Upgrade to Pro — share decks privately, control downloads, hide ads and more …

swift javascript

swift javascript

如何正当的令JS 运行如飞?!

Zoom.Quiet

May 06, 2013
Tweet

More Decks by Zoom.Quiet

Other Decks in Technology

Transcript

  1. var answer = 42 解析器 关键字 等号 标识 数字 变量声明

    标识 字面常量 标记化 → Tokens 语法分析 → 语法树 11
  2. 使用 Benchmark.js var suite = new Benchmark.Suite; suite.add('String#indexOf', function() {

    'Hello World!'.indexOf('o') > -1; }) .on('complete', function() { console.log('Fastest is ' + this.filter('fastest').pluck('name')); }) .run(); http://benchmarkjs.com/ 23
  3. 循环中常量的移动 你写的代码 JS引擎优化后的代码 for (var i = 0; i <

    100; i++) { sum += Math.sqrt(2) * i; } var temp = Math.sqrt(2); for (var i = 0; i < 100; i++) { sum += temp * i; } 代码偏移 → 精确度损失 24
  4. 删除无用代码 http://blogs.msdn.com/b/ie/archive/2010/11/17/html5-and-real-world-site- performance-seventh-ie9-platform-preview-available-for-developers.aspx 你写的代码 JS引擎优化后的代码 function test() { var a

    = 0, b = 0; for (var i = 0; i < 100; i++) { a += i; b += i * i; } return a; } function test() { var a = 0; for (var i = 0; i < 100; i++) { a += i; } return a; } 25
  5. 自动内联 你写代码 js引擎优化后的代码 function square(x) { return x * x;

    } function f(x) { var sum = 0; for (var i = 0; i < x; i++) { sum += square(i); } return sum; } function f(x) { var sum = 0; for (var i = 0; i < x; i++) { sum += i * i; } return sum; } http://ariya.ofilabs.com/2013/04/automatic-inlining-in-javascript-engines.html 30
  6. V8 内联跟踪 http://floitsch.blogspot.com/2012/03/optimizing-for-v8-inlining.html d8 --trace-inlining example.js Did not inline InstantiateFunction

    called from Instantiate (target text too big). Did not inline Instantiate called from Instantiate (target not inlineable). Did not inline called from Instantiate (target not inlineable). Did not inline ConfigureTemplateInstance called from Instantiate (target not inlineable). Did not inline ToObject called from valueOf (target not inlineable). Did not inline FunctionSourceString called from toString (target not inlineable). Did not inline InstantiateFunction called from Instantiate (target text too big). Did not inline Instantiate called from Instantiate (target not inlineable). Did not inline ConfigureTemplateInstance called from Instantiate (target not inlineable). Inlined square called from f. Inlined square called from f. 31 译者说明:本人编译的 V8 (version 3.17.15.4) 运行该条命令后并没 有得到上面的结果。 使用命令: d8 --trace-inlining --stress-opt example.js 在有压力测试的 时候得到如右图的结果。 V8 的 debug 版本支持命令: d8 --trace_ic example.js 可以输出更为 详细的内联代码说明。
  7. 源码, 语法树, 内存 http://ariya.ofilabs.com/2012/07/lazy-parsing-in-javascript-engines.html function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } alert(add(40, 2)); { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [ { "type": "Identifier", "name": "x" }, { "type": "Identifier", "name": "y" } ], "defaults": [], "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "+", "left": { "type": "Identifier", "name": "x" }, "right": { "type": "Identifier", "name": "y" } } } ] }, "rest": null, "generator": false, "expression": false }, { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "mul" }, "params": [ { "type": "Identifier", "name": "x" }, { "type": "Identifier", "name": "y" } ], "defaults": [], "body": { "type": "BlockStatement", "body": [ { "type": "ReturnStatement", "argument": { "type": "BinaryExpression", "operator": "*", "left": { "type": "Identifier", "name": "x" }, "right": { "type": "Identifier", "name": "y" } } } ] }, "rest": null, "generator": false, "expression": false }, { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "alert" }, "arguments": [ { "type": "CallExpression", "callee": { "type": "Identifier", "name": "add" }, "arguments": [ { "type": "Literal", "value": 40, "raw": "40" }, { "type": "Literal", "value": 2, "raw": "2" } ] } ] } } ] } { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "add" }, "params": [ { "type": "Identifier", "name": "x" }, { "type": "Identifier", "name": "y" } ] }; 33
  8. 深入理解 function add(x, y) { return x + y; }

    声明一个 add 方法. 接受参数 x 和 y. 包含一条有返回值的语句. 返回的是 x + y 二元运算后的结果. function mul(x, y) { return x * y; } 声明一个 mul 方法. 接受参数 x 和 y. 包含一条有返回值的语句. 返回的是 x × y 二元运算后的结果. alert(add(40, 2)); 调用 alert 方法. alert参数是 add方法 以40 和 2 为参数执行后的 返回值. 34
  9. 惰性加载 function add(x, y) { return x + y; }

    声明一个 add 方法,包含的方法体是 “{ return x + y; }”. function mul(x, y) { return x * y; } 声明一个 mul 方法,包含的方法体是 “{ return x * y; }”. alert(add(40, 2)); 调用 alert 方法. alert参数是 add方法 以40 和 2 为参数执行后的返 回值. 调用add方法,此时 add 还没有被解析. 解析方法体 “{ return x + y; }”. 接受参数 x 和 y.返回的是 x + y 二元运算后的结果. 35
  10. 对象结构变化 function Vehicle() { this.color = 'white'; this.speed = 0;

    } var car = new Vehicle(); car.color = 'black'; color speed var motorbike = new Vehicle(); motorbike.wheels = ['front', 'back']; car.maker = 'BMW'; color speed maker color speed wheels 37
  11. 固定结构 http://ariya.ofilabs.com/2012/02/javascript-object-structure-speed-matters.html var universe = { answer: 42 }; //

    do something else universe.panic = false; var universe = { answer: 42, panic: true }; // do something else universe.panic = false; 提示: 单一的内联缓存减少影响 40
  12. 避免出现条件性的对象结构变化 var vehicle = { color: 'blue' }; if (currentYear

    > 2014) vehicle.backupCamera = new Camera(); var vehicle = { color: 'blue', backupCamera: null }; if (currentYear > 2014) vehicle.backupCamera = new Camera(); 41
  13. 使用最小化的对象结构 http://www.youtube.com/watch?v=Vo72W1HWeFI var tick = new Date(); for (var i

    = 0, j = 0; i < 4e4; ++i) { var delta = new Date(); delta = delta - tick; tick = new Date(); j += delta; } var tick = Date.now(); for (var i = 0, j = 0; i < 4e4; ++i) { var delta = Date.now() - tick; tick = Date.now(); j += delta; } 大量 小的 Date 对象 43
  14. 追踪V8的垃圾回收 d8 --trace-gc example.js new Date() Date.now() 56 ms: Scavenge

    1.8 (36.0) -> 0.9 (36.0) MB, 2.8 ms 73 ms: Scavenge 1.8 (36.0) -> 0.9 (37.0) MB, 2.8 ms 89 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms 109 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms 126 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms 141 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms 159 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms 176 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms 192 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms 207 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms 54 ms: Scavenge 1.8 (36.0) -> 0.9 (36.0) MB, 2.9 ms 67 ms: Scavenge 1.8 (36.0) -> 0.9 (37.0) MB, 2.7 ms. 44
  15. 任务分类 数组 [1, 2, 3] 对象 { a: 1, b:

    3 } 括号里的表达式 (x + y) 方法 function test() { } 标识 x 字面量 42 ? 46
  16. 原始分类 function parsePrimaryExpression() { if (match('[')) return parseArrayInitialiser(); if (match('{'))

    return parseObjectInitialiser(); if (match('(')) return parseBracketExpression(); if (matchKeyword('function')) return parseFunctionExpression() if (matchKeyword('this')) return createThisExpression(); if (match('/') || match('/=')) return createRegExpLiteral(); var token = lex(); if (token.type === Token.Identifier) return createIdentifier(token); if (token.type === Token.NullLiteral) return createNullLiteral(); if (token.type === Token.NumericLiteral) return createNumericLiteral(token); if (token.type === Token.StringLiteral) return createStringLiteral(token); if (token.type === Token.BooleanLiteral) return createBooleanLiteral(token); return throwUnexpected(token); } 47
  17. 优化后的分类 function parsePrimaryExpression() { var token = lookahead(); if (token.type

    === Token.Identifier) return createIdentifier(token); if (token.type === Token.NumericLiteral) return createNumericLiteral(token); if (token.type === Token.StringLiteral) return createStringLiteral(token); if (matchKeyword('this')) return createThisExpression(); if (matchKeyword('function')) return parseFunctionExpression() if (token.type === Token.BooleanLiteral) return createBooleanLiteral(token); if (token.type === Token.NullLiteral) return createNullLiteral(); if (match('[')) return parseArrayInitialiser(); if (match('{')) return parseObjectInitialiser(); if (match('(')) return parseBracketExpression(); if (match('/') || match('/=')) return createRegExpLiteral(); return throwUnexpected(lex()); } 49
  18. 使用短路 http://ariya.ofilabs.com/2011/11/matching-a-decimal-digit.html function isDigit(ch) { return '0123456789'.indexOf(ch) >= 0; }

    function isDigit(ch) { return ch !==' ' && '0123456789'.indexOf(ch) >= 0; } 字符 数字 空格 50
  19. 对象集合 http://ariya.ofilabs.com/2012/08/determining-objects-in-a-set-examples-in-javascript.html var valid_words = { 'foobar': true, 'bar': true,

    'baz': true, 'quux': true }; function is_valid(word) { return valid_words.hasOwnProperty(word); } is_valid('fox'); // false 字典 拼写检查 可选替代方案: 数组查找, switch 语句, 前缀/后缀树, 完美散列 51
  20. 分支条件 function is_valid(word) { switch (word.length) { case 3: return

    word === 'bar' || word === 'baz'; case 4: return word === 'quux'; case 6: return word === 'foobar'; } return false; } 筛选 #1: 长度 http://ariya.ofilabs.com/2012/08/determining-objects-in-a-set-examples-in-javascript.html 52
  21. 快就够了? Alice Bob Chuck Dan ... Bob Alice Dan Chuck

    ... 通讯簿 排序 速度如何? 10 个联系人排序用时2 ms 54
  22. 实现代码 Array.prototype.swap = function (i, j) { var k =

    this[i]; this[i] = this[j]; this[j] = k; } function sort(list) { var items = list.slice(0), swapped = false, p, q; for (p = 1; p < items.length; ++p) { for (q = 0; q < items.length - p; ++q) { if (items[q + 1] < items[q]) { items.swap(q, q + 1); swapped =true; } } if (!swapped) break; } return items; } 冒泡排序 ??? 坑爹啊~~~ 55
  23. 用于调试的预留代码 Array.prototype.swap = function (i, j) { var k =

    this[i]; this[i] = this[j]; this[j] = k; } Array.prototype.swap = function (i, j) { Log({ name: 'Array.prototype.swap', lineNumber: 1}); var k = this[i]; this[i] = this[j]; this[j] = k; } http://ariya.ofilabs.com/2012/01/scalable-web-apps-the-complexity-issue.html 56
  24. 执行时间分析 0 250000 500000 0 1000 调用 swap() 500 参数规模

    http://ariya.ofilabs.com/2012/01/scalable-web-apps-the-complexity-issue.html 57
  25. 追踪程序启动时间 https://gist.github.com/1823129 jQuery Mobile 启动日志 4640 个方法调用 jquery.js 26 jQuery

    jquery.js 103 init undefined, undefined, [object Object] jquery.js 274 each (Function) jquery.js 631 each [object Object], (Function), undefined jquery.js 495 isFunction [object Object] jquery.js 512 type [object Object] jquery.mobile.js 1857 [Anonymous] jquery.mobile.js 642 [Anonymous] jquery.mobile.js 624 enableMouseBindings jquery.mobile.js 620 disableTouchBindings http://ariya.ofilabs.com/2012/02/tracking-javascript-execution-during-startup.html 58
  26. 更多的资料 Vyacheslav Egorov http://mrale.ph/ Florian Loitsch http://floitsch.blogspot.com/ Andy Wingo http://wingolog.org/

    http://blip.tv/jsconf/jsconf2012-andy-wingo-6139109 Michael Starzinger: The Footprint of Performance http://www.youtube.com/watch?v=ZhshEZIV2F4 Google I/O 2012 - Breaking the JavaScript Speed Limit with V8 http://www.youtube.com/watch?v=UJPdhx5zTaw 64