javascript - google - ¿Por qué Closure Compiler insiste en agregar más bytes?
google closure (3)
Creo que esto es lo que está pasando, pero de ninguna manera estoy seguro ...
El código que causa la inserción de comas es tryMinimizeStringArrayLiteral
en PeepholeSubstituteAlternateSyntax.java .
Ese método contiene una lista de caracteres que probablemente tengan una codificación Huffman baja y, por lo tanto, es preferible dividirlos que otros caracteres. Puedes ver el resultado de esto si intentas algo como esto:
"a b c d e f g".split(" "); //Uncompiled, split on spaces
"a,b,c,d,e,f,g".split(","); //Compiled, split on commas (same size)
El compilador reemplazará el carácter que intenta dividir con uno que considere favorable. Lo hace iterando sobre los caracteres de la cadena y encontrando el carácter de división más favorable que no ocurre dentro de la cadena:
// These delimiters are chars that appears a lot in the program therefore
// probably have a small Huffman encoding.
NEXT_DELIMITER: for (char delimiter : new char[]{'','', '' '', '';'', ''{'', ''}''}) {
for (String cur : strings) {
if (cur.indexOf(delimiter) != -1) {
continue NEXT_DELIMITER;
}
}
String template = Joiner.on(delimiter).join(strings);
//...
}
En el fragmento de código anterior puede ver la matriz de caracteres que el compilador dice ser óptimo para dividir. La coma es la primera (por lo que en mi ejemplo de espacio anterior, los espacios han sido reemplazados por comas).
Creo que la inserción de comas en el caso en el que la cadena a dividir es la cadena vacía puede ser simplemente un descuido. No parece haber ningún tratamiento especial para este caso, por lo que se trata como cualquier otra llamada split
y cada carácter se une con el primer carácter apropiado de la matriz que se muestra en el fragmento de código anterior.
Otro ejemplo de cómo el compilador trata con el método de split
:
"a,;b;c;d;e;f;g".split(";"); //Uncompiled, split on semi-colons
"a, b c d e f g".split(" "); //Compiled, split on spaces
Esta vez, dado que la cadena original ya contiene una coma (y no queremos dividir el carácter de la coma), no se puede elegir la coma de la matriz de caracteres con codificación Huffman baja, por lo que la siguiente mejor opción es seleccionado (el espacio).
Actualizar
Siguiendo algunas investigaciones adicionales sobre esto, definitivamente no es un error. Este comportamiento es en realidad por diseño, y en mi opinión es una pequeña optimización muy inteligente, si se tiene en cuenta que el compilador Closure tiende a favorecer la velocidad del código compilado sobre el tamaño.
Arriba mencioné la codificación de Huffman un par de veces. El algoritmo de codificación de Huffman, explicado de manera muy simple, asigna un peso a cada carácter que aparece en el texto a codificar. El peso se basa en la frecuencia con la que aparece cada personaje. Estas frecuencias se utilizan para construir un árbol binario, con el carácter más común en la raíz. Eso significa que los caracteres más comunes son más rápidos de decodificar, ya que están más cerca de la raíz del árbol.
Y dado que el algoritmo de Huffman es una gran parte del algoritmo DEFLATE usado por gzip. Por lo tanto, si su servidor web está configurado para usar gzip, sus usuarios se beneficiarán de esta optimización inteligente.
Si le doy a Closure Compiler algo como esto:
window.array = ''0123456789''.split('''');
Se "compila" a esto:
window.array="0,1,2,3,4,5,6,7,8,9".split(",");
Ahora como puedes ver, eso es más grande. ¿Hay alguna razón por la que Closure Compiler esté haciendo esto?
Este problema se solucionó el 20 de abril de 2012, consulte la revisión: https://code.google.com/p/closure-compiler/source/detail?r=1267364f742588a835d78808d0eef8c9f8ba8161
Irónicamente, la split
en el código compilado no tiene nada que ver con la split
en la fuente. Considerar:
Source : a = ["0","1","2","3","4","5"]
Compiled: a="0,1,2,3,4,5".split(",")
Aquí, split
es solo una forma de representar matrices largas (el tiempo suficiente para que la suma de todas las comillas + comas sean más largas que split(","")
). Entonces, ¿qué está pasando en tu ejemplo? Primero, el compilador ve una cadena Función aplicada a una constante y la evalúa de inmediato:
''0123456789''.split('''') => ["0","1","2","3","4","5","6","7","8","9"]
En algún momento posterior, cuando se genera una salida, el compilador considera que esta matriz es "larga" y la escribe en la forma "dividida" anterior:
["0","1","2","3","4","5","6","7","8","9"] => "0,1,2,3,4,5,6,7,8,9".split(",")
Tenga en cuenta que toda la información sobre split('''')
en la fuente ya se perdió en este punto.
Si la cadena de origen fuera más corta, se generaría en forma de matriz de matriz, sin división adicional:
Source : a = ''0123''.split('''')
Compiled: a=["0","1","2","3"]