Javascripty por que no
Comparar la Velocidad
con el Tocino
Isabel Cabezas@[email protected]@techdencias.net
FrontEnd Sharepointer en pasionaDivulgadora Tecnológica en Fundación Techdencias
Toni Recio@[email protected]@techdencias.net
Responsable de Tecnología e Innovación en pasionaDivulgador Tecnológico en Fundación Techdencias
www.pasiona.com
Agenda
1. ¡Jugando con HiPig!2. Navegador y JavaScript3. ¿Por qué mi aplicación va lenta?4. Cinco principios sobre eficiencia: Controla la memoria Eficiencia en la gestión de objetos Rapidez matemática Domina los arrays Obtener objetos del DOM
Principios CERDO
for (var i = 0; i < 100; i++) {
HighFive.game.onTouch();
}
Contador de FPS
Benchmark mode
La piara
Puntuación
var start = Date.now();
for (var i = 0; i < 100; i++) {
HighFive.game.onTouch();
}
var total = (Date.now()) - start;
Time
Matriz de cerditos
Cada cerdito se tiene cuatro direcciones
Selecciona un cerdito al
tocarlo
Genera una lista de vecinos
cerdos para rotar
Se rota el cerdito
Repetir toda la lista de vecinos
Matriz => Array
Cerdo => Objeto
Direcciones del jugador => Propiedades del Objeto
Números Operaciones matemáticasy operaciones con arrays
Direcciones de memoria
Animaciones
Aplicaciones Lentas
El mal código genera aplicaciones lentas.
FPS en Firefox
Glitchs
Lo que de verdad importa...en el rendimiento visual del juego
Net
wo
rkin
g
HTM
L
CSS
Co
lecc
ion
es
Java
Scri
pt
Loca
lizac
ión
MO
Nat
ivo
Form
ate
o
Co
nst
. b
loq
ue
s
Dis
eñ
o
Vis
ual
izac
ión
Pila de subsistemas del navegador
+Código
Dibujar
1
2 7
43 8 9
5 6
DOMTreeAnálisis
1
2 7
43 8 9
5 6
Display TreeMotorJSMotor JS Navegador
Repetir 60 veces por segundo!
16.67ms
Profilers... o cómo saber por dónde se van los milisegundos
MotorJS
Tu código
Otrossubsistemas
Profilers hay muchos...JavaScript Profiling With The Chrome Developer Tools
JavaScript Profiler 3.0
WebKit’s Web Inspector
Spy-JS
YUI 2: Profiler
Firebug
Firefox Developer Tools
Internet Explorer F12 UI Responsiveness Tool
http://msdn.microsoft.com/library/ie/aa740471
DEMO
Análisis del resultado
MotorJS
GC
El Garbage Collector (GC)
¿Cómo funciona el GC?
Obj1 Obj1a Obj1b Root Obj2 Obj2a Obj2b Obj2c
Obj2d C-1 C-2 Obj2e Obj3 ... ... ...
... ... ... ... ... ... ... ...
... C-1a ... C-1b C-1c C-1a1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1 C-1b1
Programa ProgramaInicializado
Objetospequeños
Objetosgrandes
Zero out
Cuándo se llama al GC??
Cada llamada a new, o cada reserva implícita de una asignación de
memoria. Todas las nuevas reservas de memoria son “baratas” (en
coste de ejecución) hasta que el pool se agota.
Cuando el pool se agota y no quedan más localizaciones libres
entonces el motor fuerza una “collecta”. ¿Nos acordamos de los
16.67ms?
Cada petición de memoria te lleva más cerca de una
pausa causada por el GC.
Principio #1Controla la memoria
Un poquito de codigo...
8. var HiPig = {};9.10. (function (root) {11.12. function Game() {13. this.boardSize = 26;14. this.matrix = new Array(this.boardSize);15. this.tmpMatrix = new Array();16. this.nextNodesStack = new Array();17. this.currentNodesList = new Array();18. this.gameInProgress = false;19. this.gameScore = 0;20. this.recordScore = 0;21. }
Un poquito de codigo...
28. function Pig(n, e, s, w) {29. Object.defineProperty(this, "north", {30. get: function () { return nVal; },31. set: function (value) { nVal = value; }32. enumerable: true,33. configurable: true34. });
/** Se han omitido las propiedades east, south, west **/
53. var nVal = n;54. var eVal = e;55. var sVal = s;56. var wVal = w;
}
Un poquito de codigo...56. function Toni(n, e, s, w) {57. Pig.apply(this, arguments);58. this.name = "Toni";59. } 60. Toni.prototype = new Pig();61.62. function Isa(n, e, s, w) {63. Pig.apply(this, arguments);64. this.name = "Isa";65. }66. Isa.prototype = new Pig();67.68. Game.prototype.initialize = function () {69. for (var i = 0; i < this.boardSize; i++) {70. this.matrix[i] = new Array(this.boardSize);71. } 72. }
Las posturas de Isa
new Isa(0, 1, 1, 0) = “ES”
Isa(n, e, s, o) {
N
E
S
O
(0, 0, 1, 1)
(1, 0, 0, 1) (1, 1, 0, 0)
(0, 1, 1, 0)
Rotando330. Game.prototype.rotate = function (node) {
331. var x = node[0]; var y = node[1];
332.
333. if (root.game.matrix[x][y]["north"] &&
root.game.matrix[x][y]["east"]) {
330. //si el pig mira al NE, su nueva posición es NO
331. root.game.tmpMatrix.push([x, y, "NO", 1]);332. }
333. else if (root.game.matrix[x][y]["east"] &&
root.game.matrix[x][y]["south"]) {
//si el jugador mira al ES, su nueva posición es SW
330. root.game.tmpMatrix.push([x, y, "SO", 1]);331. }
332. /** Se han omitido los otros dos giros **/
333. }
i j
17 23 “NO” 1
Dibujando el giro
366.Game.prototype.commitRotation = function () {367.
368. var node = this.tmpMatrix.pop();369. while (node) {
370. if (node[2] == "NE") {371. if (this.matrix[node[0]][node[1]].name == "Toni") {
372. this.matrix[node[0]][node[1]] = new Toni(1, 1, 0, 0);373. } else {
374. this.matrix[node[0]][node[1]] = new Isa(1, 1, 0, 0);375. }
/** y mas if’s **/
17 23 “NE” 1
¿Dónde va “old” Toni?
Reduciendo la reserva de memoria
(0, 0, 1, 1)
(1, 0, 0, 1) (1, 1, 0, 0)
(0, 1, 1, 0)
N =1
S = 0
Isa(n, e, s, o) {
E =0
O=1
N =0
S = 1
E =1
O= 0
Rotacion mejorada
347.Game.prototype.rotateFast = function (node) {348. var x = node[0];349. var y = node[1];350. if (root.game.matrix[x][y].north && root.game.matrix[x][y].east) {351. root.game.tmpMatrix.push([x, y, "north", 0]);
352. root.game.tmpMatrix.push([x, y, "south", 1]);353. } else if (... )
17 23 “north” 0
17 23 “south” 1
Rotacion mejorada
399. Game.prototype.commitRotation = function () {400.401. var node = this.tmpMatrix.pop();402. while (node) {403. if (node[2] == "north") {
404. this.matrix[node[0]][node[1]].north = node[3];405. } else if (node[2] == "east") {
406. this.matrix[node[0]][node[1]].east = node[3];407.
17 23 “north” 0
17 23 “south” 1
Resultados
0 2000 4000 6000 8000 10000 12000 14000
Original
Memoria
ResultadosOriginal Tiempo: 13001 milisegundos
Cerditos rotados: 11814
Ahorro de Memoria Tiempo: 4248 milisegundos
Cerditos rotados: 11814
Novedades en Chakra
• Ventajas de la Recolección de basura concurrente.
• Reducir esperas gracias a recursos hardware libres.
• Recolecciones parciales (tiempo restringido)
• Páginas separadas para objetos grandes y pequeños (evita la fragmentación)
ProgramaBarrido
InicioPrograma
BarridoZero
Pages
FOREGROUND THREAD
BACKGROUND THREAD
Inicio Programa Rescan Marcado
Resumiendo principio 1 - Controla la memoria
Evitar crear objetos innecesarios.
Usar colecciones de objetos, cuando se posible.
Ser cuidadoso con los patrones de petición de memoria.
Principio #2Eficiencia en la gestión de objetos
var p1;p1.north = 1;p1.south = 0;
var p2;p2.south = 0;p2.north = 1;
north 1
south 0
north 1
north
south
south 0
north 1
south 0
south
north
Base Type “{}”
Type “{north}” Type “{south}”
Base Type “{}”
Type “{south, north}”Type “{north, south}”
Tipado interno y la importancia del orden
No añadir propiedades de forma condicionalfunction Player(direction) {
if (direction = “NE”) {this.n = 1;this.e = 1;
}else if (direction = “ES”) {
this.e = 1;this.s = 1;
}...
}
var p1 = new Player(“NE”); // p1 type {n,e}var p2 = new Player(“ES”); // p2 type {e,s}
function Player(north,east,south,west) {this.n = north;this.e = east;this.s = south;this.w = west;
}
var p1 = new Player(1,1,0,0);//p1 type {n,e,s,w}var p2 = new Player(0,0,1,1);//p2 type {n,e,s,w}
p1.type != p2.type p1.type == p2.type
No inicializar en el prototipo
function Player(name) {...
};
Player.prototype.n = null;Player.prototype.e = null;Player.prototype.s = null;Player.prototype.w = null;
var p1 = new Player("Jodi"); //p1 type{}var p2 = new Player("Mia"); //p2 type{}var p3 = new Player("Jodi"); //p3 type{}
p1.n = 1; //p1 type {n}p2.e = 1; //p2 type {e}
function Player(name) {this.n = null;this.e = null;this.s = null;this.w = null;...
}
var p1 = new Player("Jodi"); //p1 type{n,e,s,w}var p2 = new Player("Mia"); //p2 type{n,e,s,w}var p3 = new Player("Jodi"); //p3 type{n,e,s,w}
p1.n = 1; //p1 type{n,e,s,w}p2.e = 1; //p2 type{n,e,s,w}
p1.type != p2.type != p3.type p1.type == p2.type == p3.type
Getters y Setters
function Player(north, east, south, west) {Object.defineProperty(this, "n", {
get : function() { return nVal; }, set : function(value) { nVal=value; }, enumerable: true, configurable: true
});Object.defineProperty(this, "e", {
get : function() { return eVal; }, set : function(value) { eVal=value; }, enumerable: true, configurable: true
});...
}var p = new Player(1,1,0,0);var n = p.n;p.n = 0;...
function Player(north, east, south, west) {this.n = north;this.e = east;this.s = south;this.w = west;...
}
var p = new Player(1,1,0,0);var n = p.n;p.n = 0;...
LENTO RÁPIDO
Corrigiendo el código - Lo que tenemos (I)function Player(n, e, s, w) {
Object.defineProperty(this, "north", {
get: function () { return nVal; },
set: function (value) { nVal = value; },
enumerable: true,
configurable: true
});
Object.defineProperty(this, "east", {
get: function () { return eVal; },
set: function (value) { eVal = value; },
enumerable: true,
configurable: true
});
...
Corrigiendo el código - Lo que tenemos (II)...
Object.defineProperty(this, "south", {
get: function () { return sVal; },
set: function (value) { sVal = value; },
enumerable: true,
configurable: true
});
Object.defineProperty(this, "west", {
get: function () { return wVal; },
set: function (value) { wVal = value; },
enumerable: true,
configurable: true
});
...
Corrigiendo el código - Lo que tenemos (III)...
var nVal = n;
var eVal = e;
var sVal = s;
var wVal = w;
}
Corrigiendo el código - Lo que deberíamos tener
function FastPlayer(n, e, s, w) {
this.north = n;
this.east = e;
this.south = s;
this.west = w;
}
0 2000 4000 6000 8000 10000 12000 14000
Original
Memoria
Objetosrápidos
Original Tiempo: 13001 milisegundos
Cerditos rotados: 11814
Ahorro de Memoria Tiempo: 4248 milisegundos
Cerditos rotados: 11814
Objetos rápidos Tiempo: 3020 milisegundos
Cerditos rotados: 11814
Resultados
Resumiendo principio 2 - Eficiencia en la gestión de objetos
No añadir propiedades de forma condicional.
Añadir propiedades en el constructor.
Getters i Setters sólo cuando sean necesarios
Principio #3Rapidez Matemática
Números en JavaScript
31 bits
Entero 31-bit (tipado = “smi”) 1 bit
1
31 bits
Dirección de memoria1 bit
032 bits
32 bits
FloatsEnteros de 32-bit
PILA (STACK) MONTÓN (HEAP)
Longitud fija, acceso rápido Longitud variable, acceso lento
Boxed
Todos los números en JS son flotantes:• Muy flexible• Muy poco eficientes
Usando numeros de 31 bits
STACK
0x00000003north:
0x005e4148east:
0x005e4160south:
String
“east”
Number
0.1
Number
0x1
0x005e4170west:
HEAP
Posición de memoria0…01001000
LENTO
LENTO
LENTO
var north = 1;
var east = "east";var south = 0.1;var west = 0x1;
function Pig(north, south, east, west) {
...}
var p = new Pig(north,south,east,west);
Representación de un 1= 0…00000011
Formas de usar un entero (smi)
1) Declarando enteros
var north = 1;
• Internamente sabe que es un entero.
• Mientras no forcemos una conversión se guardará en el stack.
• Esta es una de las mejoras de los motores JS de navegadores modernos
Formas de usar un entero (smi)
1) Declarando enteros
2) Operaciones con enteros
var a = 5;var b = 2;r = ((a + b) / 2) |0 ;
• Añadir |0 es una forma de especificar el tipo en el cálculo
Formas de usar un entero (smi)
3) Especialización de los cálculos
function Distance(p1, p2) {var dx = p1.x - p2.x;var dy = p1.y - p2.y;var d2 = dx * dx + dy * dy;return Math.sqrt(d2);
}
var point1 = {x:10, y:10};var point2 = {x:20, y:20};var point3 = {x:1.5, y:1.5}; var point4 = {x:0x0AB, y:0xBC};
Distance(point1, point3);Distance(point2, point4);
Formas de usar un entero (smi)
3) Especialización de los cálculos
function DistanceFloat(p1, p2) {var dx = p1.x - p2.x;var dy = p1.y - p2.y;var d2 = dx * dx + dy * dy;return Math.sqrt(d2);
}
var point1 = {x:10, y:10};var point2 = {x:20, y:20};var point3 = {x:1.5, y:1.5}; var point4 = {x:0x0AB, y:0xBC};
DistanceInt(point1, point2);
DistanceFloat(point3, point4);
function DistanceInt(p1,p2) {var dx = p1.x - p2.x;var dy = p1.y - p2.y;var d2 = dx * dx + dy * dy;return (Math.sqrt(d2) | 0);
}
• Declarando enteros
• Operaciones con enteros
• Especialización de los cálculos
Resumiendo principio 3 - Rapidez matemática
Principio #4Domina los arrays
Arrays pre-reservados
var a = new Array(100);for (var i = 0; i < 100; i++) {a[i] = i + 2;
}
var a = new Array();for (var i = 0; i < 100; i++) {a.push(i + 2);
}
0 ?
?+1 ??
…0 100
LENTO RÁPIDO
Recorrer arrays eficientemente
var a = new Array(100);var total = 0;
for (var item in a) {total += item;
};
a.forEach(function(item){total += item;
});
for (var i = 0; i < a.length; i++) { total += a[i];
}
var a = new Array(100);var total = 0;cachedLength = a.length;for (var i = 0; i < cachedLength; i++) { total += a[i];
}
LENTO
RÁPIDO
Comparativa: http://jsperf.com/for-vs-foreach/5
SUPER RÁPIDO
var a = new Array(100);var cachedLength = a.length-1;do {
total += a[i]);} while (cachedLength--);
Representación de un array en memoria
var a = new Array();
a[0] = 1;
a[1] = 2.3;
a[2] = "str";
Type: Int Array
Type: Int Array 1
Type: Float Array 1 2.3
Type: Var Array 1 2.3 “str”
Si mezclamos... “avisemos”
LENTO RÁPIDO
var a = new Array(100000);
for (var i = 0; i < a.length; i++) {a[i] = i;
}...//operations on the array...a[99] = “str”;
var a = new Array(100000);
a[0] = “hint”;
for (var i = 0; i < a.length; i++) {a[i] = i;
}...//operations on the array...a[99] = “str”;
Arrays tipados explícitamente
var value = 5;
var a = new Array(100);a[0] = value; // 5 - taggeda[1] = value / 2; // 2.5 - boxeda[2] = "text"; // "text" – var array
var value = 5;
var a = new Float64Array(100);a[0] = value; // 5 - no tagging requireda[1] = value / 2; // 2.5 - no boxing requireda[2] = "text"; // 0
var a = new Int32Array(100);a[0] = value; // 5 - no tagging requireda[1] = value / 2; // 2 - no tagging requireda[2] = "text"; // 0
LENTO RÁPIDO
Arrays tipados explícitamente
Type Size Description Equivalent C type
Int8Array 1 8-bit twos complement signed integer signed char
Uint8Array 1 8-bit unsigned integer unsigned char
Uint8ClampedArray 1 8-bit unsigned integer unsigned char
Int16Array 2 16-bit twos complement signed integer short
Uint16Array 2 16-bit unsigned integer unsigned short
Int32Array 4 32-bit twos complement signed integer int
Uint32Array 4 32-bit unsigned integer unsigned int
Float32Array 4 32-bit IEEE floating point number float
Float64Array 8 64-bit IEEE floating point number double
Mantener la “densidad” del array
var a = new Array(1000); //type int...for (var i = 0; i < boardSize; i++) {
matrix[i] = [1,1,0,0];}
//operating on the array...delete matrix[23];...//operating on the array
var a = new Array(1000); //type int...for (var i = 0; i < boardSize; i++) {
matrix[i] = [1,1,0,0];}
//operating on the array...matrix[23] = 0;...//operating on the array
LENTO RÁPIDO
Resumiendo principio 4 - Domina los arrays
• Pre reserva de arrays
• Recorrer arrays eficientemente
• Tipos internos y copia de arrays
• Si mezclamos avisamos
• Arrays tipados explícitamente
• Mantener la “densidad”
Principio #5Obtener objetos del DOM
Llamadas al DOMLlamar al DOM es una operación costosa, y suele ser el cuello de botella más grande de las app web.
document.getElementById('here').innerHTML += 'a';
function innerHTMLLoop() {for (var count = 0; count < 15000; count++) {
}}
function innerHTMLLoop2() {var content = '';for (var count = 0; count < 15000; count++) {
content += 'a';}document.getElementById('here').innerHTML += content;
}
150 veces más rápido
Cachea elementos completos
1) Evita estar constantemente accediendo al DOM: mejor una llamada y cachear el elemento entero
JavaScript
DOM
...//for each rotationdocument.body.game.getElementById(elID).classList.remove(oldClass)document.body.game.getElementById(elID).classList.add(newClass)...
var element = document.getElementById(elID).classList;
//for each rotationelement.remove(oldClass)element.add(newClass)...
JavaScript
DOM
this.boardSize = document.getElementById("benchmarkBox").value;
string string
this.boardSize = parseInt(document.getElementById("benchmarkBox").value);
int
El DOM devuelve siempre un string.
2) Cuidado con las conversiones: Los valores DOM por defecto son String! ¿¿¿Os había contado ya por qué no se debe comparar la velocidad con el tocino???
for (var i = 0; i < this.boardSize; i++) { for (var j = 0; j < this.boardSize; j++) {
...}
}
NOIf Type(x) == String && Type(y) == Number
Como compara JS la velocidad y el tocino
X == y?
Type(x) == Type(y)
SI
NO
Type(x) == Undefined
SI
Type(x) == Null NO Type(x) == NumberNOType(x) == String
NO NO …
true
X == null && y==undefined
SI
X == undefined && y==null
NO NOType (x) == number &&
Type (y) == stringNO …
El algoritmo de la comparacion de igualdad “abstracta”:Type(x) == Type(y)
X == y?
true
False
Si No
Type(x) == Undefined
Type(x) == Null
Si
No
Type(x) == Number
No
Si
Type(x) == String
Si
No
Type(x) == Boolean
X es el mismo objeto que y
X == y
Si
No
x == true &&x == true
X == NaN
Y == NaN
X==y
X == +0 && y == -0
X == -0 && y == +0
X == null && y==undefined
X == undefined && y==null
Type (x) == number && Type (y) == string
23,1071
If Type(x) == Boolean
Type(y) == Boolean
(Type(x) == String || Type(x) == Number) &&
Type(y) == Object
(Type(y) == String || Type(y) == Number) &&
Type(x) == Object
x == ToNumber(y)
ToNumber(x) == y.
ToNumber(x) == y.
x == ToNumber(y)
x == ToPrimitive(y)
x == ToPrimitive(y)
Más rápido que tu ojo...
setInterval(animate, 0);
setTimeout(animate, 0);
requestAnimationFrame(animate);
setInterval(animate, 1000 / 60);setTimeout(animate, 1000 / 60);
Los últimos cambios
requestAnimationFrame(animate);
setTimeout(animate, 0);
Los últimos cambios
var x = $(elID);
if (x.hasClass('imageClass2')){var newClass = 'imageClass1';var oldClass = 'imageClass2';
} else if (x.hasClass('imageClass3')){var newClass = 'imageClass1';var oldClass = 'imageClass3';
} /** … **/
x.removeClass(oldClass).addClass(newClass);
if ($(elID).hasClass('imageClass2')){$(elID).removeClass('imageClass2');$(elID).addClass('imageClass1');
} else if ($(elID).hasClass('imageClass3')){$(elID).removeClass('imageClass3');$(elID).addClass('imageClass1');
} /** … **/
Resultados
requestAnimationFrame(animate);setTimeout(animate, 0);
El uso de la CPU se reduce un 10%
ResultadosEl uso de la CPU se reduce un 10%
Resultados
0 10000 20000 30000 40000 50000 60000
Original
Memoria
Objetos rápidos
Mat, Arrays y DOM
11814 Iteraciones (tiempos)
IE Chrome Firefox
1) Cachea los elementos enteros en JS con una llamada, en lugar de hacer varias llamadas para acceder a sus nodos hijos.
2) Cuidado con las conversiones: Los valores DOM por defecto son String!
3) No dibujes más rápido de lo que usuario pueda apreciar: sobrecarga el sistema inutilmente
Resumiendo principio 5 - Obtener objetos del DOM
1) Buena experiencia de usuario2) Larga duración en la vida de la bateria
Problema resuelto!
• Principio nº1: Controla la memoria• Principio nº2: Eficiencia en la gestión de objetos• Principio nº3: Rapidez matemática• Principio nº4: Domina los arrays• Principio nº5: Obtener objetos del DOM
En resumen...
Developing High Performance Websites and Modern Apps with JavaScript Performance Toolshttp://channel9.msdn.com/Events/Build/2013/3-316
Building High-Performing JavaScript for Modern Engineshttp://channel9.msdn.com/Events/Build/2012/4-000
Developing high performance websites and modern apps with JavaScript performance tools http://channel9.msdn.com/Events/Build/2013/3-316
CHAKRA: UNDER THE HOOD http://gotocon.com/dl/goto-aar-2012/slides/SteveLucco_TheInnerWorkingsOfTheChakraJavascriptEngine.pdfhttp://wingolog.org/
Writing Fast, Memory-Efficient JavaScripthttp://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
Performance Tips for JavaScript in V8http://www.html5rocks.com/en/tutorials/speed/v8/
Explaining JavaScript VMs in JavaScript - Inline Caches http://mrale.ph/blog/2012/06/03/explaining-js-vms-in-js-inline-caches.html
Info, info, info...
Q&A