V8 разработчик здесь. Короче говоря: вы стали жертвой ловушек микро-бенчмаркинга. Реально, «Тест 1» немного более эффективен, но в зависимости от вашей общей программы разница может быть слишком мала, чтобы иметь значение.
Причина, по которой «Тест 1» более эффективен, заключается в том, что он создает меньше замыканий. Думайте об этом как:
let mathAdd = new Function(...);
for (let i = 0; i < 1000; i++) {
mathAdd();
}
против
for (let i = 0; i < 1000; i++) {
let mathAdd = new Function(...);
mathAdd();
}
Так же, как если бы вы звонили new Object()
или new MyFunkyConstructor()
, более эффективно делать это только один раз за пределами l oop, а не на каждой итерации.
Причина, по которой «Тест 1» выглядит медленнее , является артефактом настройки теста. Указанный c способ, которым jsperf.com оборачивает ваш код в функции под капотом, в этом случае побеждает механизм встраивания V8 [1]. Таким образом, в «Тесте 1» run
указывается, а mathAdd
нет, поэтому выполняется фактический вызов и фактическое добавление. В «Тесте 2», с другой стороны, и run
, и mathAdd
вставляются, компилятор впоследствии видит, что результаты не используются, и удаляет весь мертвый код, так что вы тестируете пустой l oop: он не создает функций, не вызывает функций и не выполняет добавления (кроме i++
).
Не стесняйтесь проверять сгенерированный код сборки, чтобы убедиться в этом :-) На самом деле, если вы если вы хотите создать дополнительные микробенчмарки, вам следует привыкнуть к проверке кода сборки, чтобы убедиться, что тест измеряет то, что вы думаете, что он измеряет.
[1] Я не уверен, почему; если бы мне пришлось угадывать: вероятно, существует специальная обработка для выявления того факта, что, хотя run
является новым замыканием при каждом запуске тестового примера, под ним всегда один и тот же код, но похоже, что специальный регистр применяется только к функциям в локальная область вызова, а не загрузка из цепочки контекста, как в вызове run
→ mathAdd
. Если это предположение верно, вы можете назвать это ошибкой (которой Firefox явно нет); с другой стороны, если единственное влияние заключается в том, что устранение мертвого кода в микробенчмарках больше не работает, то это, безусловно, не важная проблема, которую нужно исправить.