Обновить

Комментарии 33

хэши лучше проверять так: hash[ name ] === 1
иначе можно напороться на одно из полей, унаследованных из глобального прототипа.
>Если же нам нужно проверить просто существование переменных и их неотрицательность.
Несуществующая переменная конечно же не сможет выбросить ошибку в вашем славном примере.

>Здесь мы используем сравнение без приведения типов ===, которое в случае нечисловых переменных работает быстрее обычного сравнения на 10–20%.
Типы в примере совпадают, конвертации значений нет, в этом случае что строгое, что нестрогое сравнение работает одинаково. При разных типах строгое сравнение тут же выкинет false, чего тут скорость сравнивать-то.

>Такая конструкция отработает на 40% быстрее, чем аналогичный exec
test — эквивалент RegExp.prototype.exec(string) != null, ой, не верю в 40%… В целом, итоговой таблице сильно не хватает столбца со ссылками на тесты в разных движках, чтоб своими глазами увидеть эти 10-20-30-40-50 процентов… ;)

.test не запоминает найденные подстроки в круглых скобках (переменные RexExp.$1..n), отсюда и экономия, тоже самое в .match
К тому же вообще не запоминает найденную строку.
Для ускорения регулярок можно «не запоминающие скобки» делать /(?:\d|-)*/ вместо «запоминающих» /(\d|-)*/
Это лишь пример, понятно что регулярка глупая.

Судя по всему .match любые скобки не запоминяет в отличии от .exec? что объясняет разницу производительности.
При работе 'test' свойства у RegExp, и у RegExp instance создаются/обновляются также, как и при работе 'exec', вспомните часто встречающуюся ошибку «test работает через раз», где речь идёт об обновляемом свойстве 'lastIndex'. Это касается и RegExp.$n и проч.

Проигрыш в производительности 'exec' связан скорее всего с необходимостью при нахождении совпадений вернуть определённый массив плюс заодно обвешать его свойствами ('input', 'index' etc). Если совпадений нет, то оба метода работают одинаково, возвращая null или false (6-ой пункт 15.10.6.2 ECMA-262).
1. Можно подробнее?
2. Если значения разные, то === отработает быстрее
www.rockstarapps.com/samples/performance/
3. В статье приведены все базовые примеры. Можете поделиться ссылкой, где написано, что
test — эквивалент RegExp.prototype.exec(string) != null

У меня сомнения, что в IE так

Цифры можно получить из примеров в статье. Это совсем не сложно. Потом еще есть
dromaeo.com/?dromaeo
1. if (a && b) {} — если 'a' — не существует, то чего будет?
2. разницы нет в алгоритме для значений одного типа; по ссылке не нашёл нужного.
3. ECMA-262 пункт 15.10.6.3.

В общем, тестов нет, жаль, половина из написанного была бы опровергнута, а другая половина вышла бы разнонаправленной. ;)
НЛО прилетело и опубликовало эту надпись здесь
2. под IE прогоните — разница есть
3. IE так сильно придерживается ECMA? хмм, лол :)
Что стоит прогнать предложенные варианты кода в цикле по 50000 раз и просто убедиться?
2. Мило, от обобщений перевели стрелки на один движок, какой IE? 6-ой, 8-ой? что прогнать? статья льёт воду — там на 20% медленнее, здесь на 10-40%, где там? в каком движке? где тесты? я со всем готов согласиться, если пройдусь по вашим тестам и получу похожее.

3.IE близко придерживается экмы, не сильно меньше других, есть разночтения у всех, есть собственная оптимизация (никакого к экме не имеющая отношения), есть много чего…

что стоит прогнать
Прогоню с удовольствием, выкладывайте.
я конкретно запускал под IE6/7. 8 меня не очень волнует — пока еще он долю наберет.

Как только я соберу окружение с матрицей всех вышеуказанных тестов — дам ссылку. Прежде, чем делать какие-либо выводы каждый случае прогонял в Firebug (иногда и в IE7).
Спасибо. Теперь очевиднее. Проверил в IE6/FF3.0.1/Op9.63/Chr0.2. Между строгим и нестрогим сравнением ожидаемо разницы нет(туда-сюда летающие 1,2,3,4 процента на таких больших оборотах во всех случаях опускаю), та же самая картина со всеми условиями — простыми и вложенными (за исключением Оперы, у которой '&&' медленнее на 30%). C чем вы точно попали в точку, так это с RegExp, метод 'exec' везде кроме Хрома работает существенно медленнее, у IE дополнительно можно отметить быстрый 'search'.
неужели небеса разверзлись? :)

Стоит провести замеры в ряд тестов 10-15 — тогда разница становится очевиднее, и выплывают указанные 5-20%. Просто у браузеров большой разброс — ясными бывают только значительные разрывы в производительности.
ОК, каждый может сам сделать свои выводы, проверив в вышеуказанных версиях браузеров, я сделал для себя такие:

1. строгое сравнение значений одного типа по стандарту ничем (буква в букву) не отличается от нестрогого сравнения, приведённый тест это лишний раз подтверждает;

2. наглядный 'if-else' не уступает в скорости ни '&&', ни ":?", соответственно, использовать последние ради одной только скорости, а не ради игры на 'expression vs. statement' или ради сокращения кода — глупо;

3. метод 'test' несмотря на стандарт очевидно оптимизирован, метод 'exec', наоборот, не оптимизирован (кроме хитрого Хрома), 'exec' и 'test' работают одинаково (по стандарту) при отсутствии совпадений (выброс null/false), при их наличии производительность 'exec' падает (видимо) за счёт возвращаемого значения.

И общий вывод: как правило, ссылка непосредственно на сам тест в разы полезнее, чем проза в стиле «нужно иметь в виду, что производительность таких конструкций бла-бла-бла примерно на 10-50% меньше, чем бла-бла-бла». Когда примерно туда-сюда, когда большие разбросы, когда не указаны движки (версии), когда нет обоснований/предположений, а еcть одни обобщения на базе тестов в Firebug!!!, то это вообще ни о чём. Начитается эдакого доверчивая душа и ради гонок откажется от 'if-else', от нестрогого сравнения, начнёт делать всякие глупости вроде «быстрого» сложения значений или проверки на существование в стиле 'if(x)'…

p.s. за тест спасибо ;)
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
еще один хороший комментарий. Не помню, зачем кэшировался этот вызов. Но сейчас создавать такую переменную нет нужды — у нас всего одно обращение к string.charAt(0)
НЛО прилетело и опубликовало эту надпись здесь
проверка тега оказалась на 40% быстрее даже в IE
НЛО прилетело и опубликовало эту надпись здесь
Сумма говорите? :) a + b + c == 6 для 2 2 2, например. :)
это было актуально для нескольких indexOf :)
Улучшение читаемости стопки ифов перед одним со сложным условием — крайне спорный вердикт.
попробуйте записать в строчку десяток условий :). Например,
if ((!id || item.id === id) && (!klass || klass.test(item.className)) && (!attr || (_.attr[eql] && (_.attr[eql](item, attr, single[6]) || (attr === 'class' && _.attr[eql](item, 'className', single[6]))))) && !item.yeasss && !(_.modificators[modificator] ? _.modificators[modificator](item, ind) : modificator))
Пробовал. А вот разворачивать вот это вот в большущее дерево даже бы ради эксперимента над нервами не стал.
:) кому как удобнее. Главное, что работает одинаково быстро
Ищу в подстроке обычно вот так: if (str.indexOf('abc')+1).
Если вернётся что угодно, то true, если -1 — то выйдет 0, т.е. false.

Как у такого варианта с производительностью по сравнению с !=-1?
было одинаково, когда я проверял месяца два назад. Но кода чуть меньше :)
в теории — медленнее, так как 0 !== false
смешно все это ))
Раз уж вы «такты» считаете, можно убрать регулярку для ие в поиске по имениКласса.
то есть заменить вот это:

     klass = new RegExp('(^| +)' + klass + '($| +)');
     var nodes = root.getElementsByTagName('*'),
         i = 0,
         node;
     while (node = nodes[i++]) {
         if (klass.test(node.className)) {
             sets[idx++] = node;
         }
     }

вот на такое:

     klass = ' ' + klass + ' ';
     var nodes = root.getElementsByTagName('*'),
         i = 0,
         node;
     while (node = nodes[i++]) {
         if ((' ' + node.className + ' ').indexOf(klass)) {
             sets[idx++] = node;
         }
     }
о спасибо, долго думал, как избежать регулярки :)
Кстати, я как то в порядке эксперимента пробовал устанавливать временные styleSheets для поиска по css-селектору, в лоб это работало очень медленно, но может это будет хорошим способом узнать актуальность выборки из кэша:

(function (){

    var css = CSS.add(), // закроссбраузенный элемент коллекции document.styleSheets
        defaultView = document.defaultView;

    var isActualNodeBySelector = function (selectorFromCache, nodeFromCache) {
        css.insertRule('*{cursor:default}', 0);
        css.insertRule(selectorFromCache + '{cursor:crosshair}', 0);
        if (( defaultView ?
                defaultView.getComputedStyle(nodeFromCache, null) :
                node.currentStyle
            )['cursor'] == 'crosshair'
        ) {
            // .......... выборка из кэша актуальна
        }
        css.deleteRule(0);
        css.deleteRule(1);
    }
})()
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации