Почему Closure Compiler настаивает на добавлении большего количества байтов?

Если я дамClosure Compiler что-то вроде этого:

<code>window.array = '0123456789'.split('');
</code>

Он "компилирует" это к этому:

<code>window.array="0,1,2,3,4,5,6,7,8,9".split(",");
</code>

Теперь, как вы можете сказать, это больше. Есть ли причина, почему Closure Compiler делает это?

 Florian Margaine20 нояб. 2012 г., 14:31
Только что протестировано - это не работает в моем IE4.
 Felix Kling18 апр. 2012 г., 15:33
Может быть, потому что это быстрее (по крайней мере, в Chrome, даже если не намного):jsperf.com/empty-split-vs-comma-split Было бы интересно увидеть разницу в других браузерах ...edit: В Safari и Firefox это выглядит медленнее, хотя ... тогда я не знаю. Но в целом CC предпочитает скорость больше размера в крайних случаях.
 Ry-♦18 апр. 2012 г., 15:33
Нет, насколько я знаю, нет никаких причин, но ничто не идеально в минимизации ...
 Matt18 апр. 2012 г., 15:35
@SLaks: Если вы можете найти случай, когда.split(''); это не кросс-браузер, я съем свою клавиатуру и выложу видео на YouTube.
 qwertymk18 апр. 2012 г., 15:38
@Matt: Как ты собираешься опубликовать это, если у тебя нет клавиатуры?

Ответы на вопрос(3)

split в скомпилированном коде не имеет ничего общего сsplit в источнике. Рассматривать:

Source  : a = ["0","1","2","3","4","5"]
Compiled: a="0,1,2,3,4,5".split(",")

Вот,split это просто способ представления длинных массивов (достаточно длинных, чтобы сумма всех кавычек + запятых была больше, чемsplit(","") ). Итак, что происходит в вашем примере? Сначала компилятор видит строковую функцию, примененную к константе, и сразу же оценивает ее:

'0123456789'.split('') => ["0","1","2","3","4","5","6","7","8","9"]

В какой-то более поздний момент, при генерации выходных данных, компилятор считает этот массив «длинным» и записывает это в вышеприведенном «split» форма:

["0","1","2","3","4","5","6","7","8","9"] => "0,1,2,3,4,5,6,7,8,9".split(",")

Обратите внимание, что вся информация оsplit('') в источнике уже потеряно на данный момент.

Если бы исходная строка была короче, она была бы сгенерирована в виде массива массива без дополнительного разделения:

Source  : a = '0123'.split('')
Compiled: a=["0","1","2","3"]
 18 апр. 2012 г., 23:51
@ qwertymk - Это именно то, что он делает, не так ли? Он скомпилирует любое прямое присвоение массива строкsplit вызов до тех пор, пока количество необходимых символов меньше. Посмотрите на реализацию метода, упомянутого в моем ответе, чтобы точно узнать, что происходит.
 19 апр. 2012 г., 00:05
@qwertymk: да, они могли бы проверить, все ли строки в массиве имеют длину 1, и обеспечить оптимизацию для этого, однако, чтобы процитировать одного из сопровождающих,the single letter example... seems like a special case and I would have to question whether it's worth the effort to address
 qwertymk18 апр. 2012 г., 23:47
Так что тогда не стоит['0', '1', '2', '3', '4', '5', '6', '7'] всегда компилировать в'01234567'.split('') ?
 qwertymk18 апр. 2012 г., 23:52
@JamesAllardice: я имею в виду без пробелов и пустого разделителя.
 18 апр. 2012 г., 23:53
@qwertymk - О да, извините, я неправильно прочитал ваш комментарий. Да, это, вероятно, то, что он должен компилировать. Я думаю, что вы, возможно, столкнулись с довольно большим упущением командой компиляторов Closure!
 26 июн. 2013 г., 22:23
обновил URL и добавил дату пересмотра, так как идентификаторы редакции GIT бесполезны для заказа.
 26 июн. 2013 г., 09:46
Вы, вероятно, должны проверить этот URL.
Решение Вопроса

think это то, что происходит, но ни в коем случае не уверен ...

Код, который вызывает вставку заптыхtryMinimizeStringArrayLiteral вPeepholeSubstituteAlternateSyntax.java.

Этот метод содержит список символов, которые могут иметь низкийКодирование Хаффманаи, следовательно, предпочтительнее разделть на другие символы. Вы можете увидеть результат этого, если вы попробуете что-то вроде этого:

"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)

Компилтор заменит символ, который вы пытаетесь разделить, на тот, который он считает предпочтительным. Это делаетс путем перебора символов строки и поиска наиболее подходщего символа разделени, который не встречаетс в строке:

// 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);
  //...
}

В приведенном выше фрагменте вы можете увидеть массив символов, которые компилтор считает оптимальными дл разбивки. Сначала запта (именно поэтому в моем примере с пробелом выше пробелы были заменены заптыми).

Я считаю, что вставка заптых в случае, когда строка дл разделени влетс пустой строкой, может быть просто упущением. По-видимому, особого отношени к этому случаю не существует, поэтому оно рассматриваетс как любое другоеsplit вызов и каждый символ соединетс с первым соответствующим символом из массива, показанного в приведенном выше фрагменте.

Еще один пример того, как компилтор работает с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

На этот раз, поскольку исходна строка уже содержит заптую (а мы не хотим разбивать символ заптой), заптую нельз выбрать из массива символов с низким кодированием по Хаффману, поэтому следующий лучший выбор - выбрано (пробел).

Update

После некоторых дальнейших исследований этого, это определенно не ошибка. Такое поведение на самом деле разработано, и, на мой взглд, это очень умна небольша оптимизаци, если учесть, что компилтор Closure имеет тенденцию отдавать предпочтениеspeed скомпилированного кода по размеру.

Выше упоминал кодирование Хаффмана пару раз. Алгоритм кодировани Хаффмана, объсненный очень просто, присваивает вес каждому символу, повлющемус дл текста, который должен быть закодирован. Вес основан на частоте, с которой повлетс каждый символ. Эти частоты используютс дл построени двоичного дерева, с наиболее распространенным символом в корне. Это означает, что наиболее распространенные символы быстрее декодируютс, поскольку они находтс ближе к корню дерева.

А поскольку алгоритм Хаффмана влетс большой частью алгоритма DEFLATE, используемого gzip. Так что, если ваш веб-сервер настроен на использование gzip, ваши пользователи получат выгоду от этой умной оптимизации.

 18 апр. 2012 г., 23:38
+1 отличный ответ! Хорошая работа!
 18 апр. 2012 г., 16:48
@ Берги - я склонен согласиться. Тем не менее, я думаю, нам нужно увидеть больше тестов производительности в разных браузерах, сравнивающих разбиение на пустую строку и символы в массиве символов с низким кодированием Хаффмана, прежде чем мы сможем сказать наверняка.
 18 апр. 2012 г., 16:45
Очень хороший ответ Кажется, это ошибка ;-)
 18 апр. 2012 г., 16:54
Говоря об этом, разделение по сравнению с обычным назначением уже очень медленно:jsperf.
 18 апр. 2012 г., 16:55
@ OlegV.Volkov - Да, и компилятор Closure будет преобразовывать вызов вsplit в прямое назначение, если это приводит к более короткому коду.

Ваш ответ на вопрос