Начало
Не буду лгать - я не люблю оценивать производительность javascript кода. Эта процедура содержит для основного проекта массу "ненужного" и "бессмысленного" кода:var n = 1000; var start = (new Date()).getTime();/ for (var i = 0 ; i < n; i++) { // bla-bla-bla ... } var stop = (new Date()).getTime(); var duration = stop - start; var average = duration / n; document.writeln(average);Думаю, всем знакомы строчки, подобные этим. Меня может интересовать производительность функции или метода, а возможно и некоторого участка программы. Но я не хочу засорять свой еще сырой код всяким мусором, подобным этому. Я также не хочу это делать для функций, когда пытаюсь оценить - какой же алгоритм лучше.
Когда мне это окончательно надоело - я решил написать свой Benchmark. Задача заключалась в том, чтобы можно было оценить производительность не только функции, но и любого участка кода, начиная со строки
n
и заканчивая строкой m
.
Мотивация
Начиная работу, я понимал - вполне вероятно, что такой код уже кем-то и весьма успешно реализован. Тем не менее, я начал с нуля. После завершения я решил сравнить свое решение с работами своих предшественников (ссылки в конце). Не буду скромничать - не смотря на некоторое сходство, мое решение лучше. Аргументация следующая - при существенном сходстве реализации мой код в значительной мере более универсален.Далее я покажу - что есть, и как из него можно получить весьма удобный и простой инструмент. Частично будут рассмотрены сходства и различия настоящего решения и его предшественников.
Особенности ОО-подхода в JavaScript
Любой фрагмент кода (особенно это справедливо для JavaScript с его особым ОО-подходом) может быть телом безымянной функции. Например, кодvar arr = [100, 200, 300, 400]; var result = 0; for (var i = 0; i < arr.length; i++) { result += arr[i]; }может быть преобразован в следующий
var arr = [100, 200, 300, 400]; ((function() { var result = 0; for (var i = 0; i < arr.length; i++) { result += arr[i]; } })();
Реализация
Это значит, что для любой функции можно применить некий метод, который может выполнить дополнительные действия, а именно:Function.prototype.eval = function()Данный метод определен для встроенного объекта
Function
, вызывает его определенное количество раз, при этом запоминает длительность выполнения функции и печатает некоторую статистическую информацию о ходе выполнения.
Посмотрим на примере как эго можно использовать:
var arr = [1, 2, 3, 4]; function sum(arr) { var result = 0; for (var i = 0; i < arr.length; i++) { result += arr[i]; } return result; } // исходный код var s = sum(arr); // модифицированный код var s = sum.eval(arr);То есть, сравнивая исходный и модифицированный код, можно увидеть, что отличия минимальны. Код по прежнему чист, а результат позволяет проанализировать полученную информацию.
Особенности
Данное решение не использует таймеры отчета времени и может выполняться в разных средах, как в окне браузера, так и в самостоятельном приложении. Также содержит некоторый дополнительный код, который решает проблему кроссплатформенности.Что же было применено дополнительно? В отличия от аналогов, данный пример работает для большинства случаев - JavaScript/JScript. Для этого дополнительно определено несколько полезных свойств:
-
Function.prototype.evalCount
- целочисленный параметр хранит количество итераций, или количество раз исполнения кода, значение по умолчанию 1000. -
Function.prototype.evalDuration
- целочисленный параметр хранит продолжительность выполнения кода. -
Function.prototype.evalPrint = function()
- вспомогательная функция для вывода статистики о производительности, учитывает различия сред исполнения и вызывает соответствующий метод для вывода количества итераций и продолжительности исполнения кода.
По умолчанию, производится оценка и выводится время исполнения кода для 1000 итераций. Параметр
Function.prototype.evalDuration
вычисляется в процессе и не имеет значения по умолчанию.
Естественно, эти параметры можно переопределить, например, изменить количество итераций, или переопределить свой метод отображения статистики. При чем, это можно сделать как глобально через прототип, так и конкретно для определенной функции. Например:
sum.evalCount = 10240; // 10K iterations var result = sum.eval(1, 2, 3, 4);
Преимущества
Предложенная методика в отличие от аналогов1. позволяет легко внедрить в свой код возможности оценки производительности с минимальными изменениями основного кода;
2. имеет расширенные возможности контроля;
3. она независима от текущей платформы и позволяет использовать данное расширение без изменений как в среде JavaScript, так и в JScript (Windows Scripting Host).
Полное решение
Решение платформно-независимо. Тестировалось для IE6, IE7, FF2.0.0.15, FF3.0.7 и Windows Scripting Host. Распространяется по лицензии GPL. Листинг исходного кода доступен по этой ссылке. Там же - ссылка на скачивание.Ссылки по теме
1. John Resig's blog2. webtoolkit site
" Скачать исходный код можно по этой ссылке. "
ReplyDelete- а вот с этим проблема, т.к по ссылке GOOGLE предоставляет страничку с ЛИСТИНГОМ программы - скачать не получается, а копипаста не удобна да и не корректна!
подскажите, как получить код ОДНИМ файлом, без лишних телодвижений? (или я невнимательный и DOWNLOAD доступен?)
Вы правы, фраза не совсем корректна и я ее подкорректировал. Ссылка дана исключительно для отслеживания переходов по ссылкам. Однако DOWNLOAD доступен. Чтобы скачать "чистый" код без разметки - найдите во вставке справа текст со ссылкой "View raw file".
ReplyDeleteспасибо, теперь получилось
ReplyDeleteХорошая статья - Как измерить скорость работы Javascript?
ReplyDelete