perf(classnames): use arguments instead spread#467
Conversation
packages/classnames/classnames.tsx
Outdated
| let className = ''; | ||
| const uniqueCache = new Set(); | ||
| const classNameList = strings.join(' ').split(' '); | ||
| const classNameList: string[] = [].slice.call(arguments); |
There was a problem hiding this comment.
Нужно поправить тип Array<string | undefined>
419604e to
a5a644e
Compare
| const uniqueCache = new Set(); | ||
| const classNameList = strings.join(' ').split(' '); | ||
| // Use arguments instead rest operator for better performance. | ||
| const classNameList: Array<string | undefined> = [].slice.call(arguments); |
There was a problem hiding this comment.
- ломается поведение при вызове
classnames('a b')(да, оно сейчас не зафиксировано в unit-тестах, ноstrings.join(' ').split(' ')было сделано именно для такого кейса) - в старых версиях V8
[].slice.call(arguments)медленнее цикла for, в который транслируется...strings(функция с передачей arguments за пределы scope не оптимизировалась https://github.com/petkaantonov/bluebird/wiki/optimization-killers#32-leaking-arguments)
There was a problem hiding this comment.
Да и сейчас for пока что как минимум не хуже остальных способов, а slice наоборот один из самых медленных вариантов
http://jsbench.github.io/#1e36f485d47f9cf8009eec50a1b80457 как один из примеров бенчмарка способов конверсии arguments в массив
There was a problem hiding this comment.
В итоге оставляем пока рест оператор?
There was a problem hiding this comment.
А давайте вместо slice сделаем просто 2 for?
http://jsbench.github.io/#0eac5d083e6b6e05a1614f26feefd1df
Спойлер:
PR (slice)
227,190 ops/sec
Предложение (2 x for, включая кейс classnames('a b'))
373,978 ops/sec
Актуальный код (rest)
133,817 ops/sec
There was a problem hiding this comment.
В бенчмарке http://jsbench.github.io/#0eac5d083e6b6e05a1614f26feefd1df баг в строке for (let i; i < arguments.length; i++) {
There was a problem hiding this comment.
У нас не будет for of в любом случае, пока мы поддерживаем ie11, сейчас for of компилируется в обычный for(;;)
There was a problem hiding this comment.
@victor-homyakov примеры со slice заранее не честные, т.к. у них пропущен кейс classnames('a b'), т.е. это не 2 класса, а один. Если в примеры со slice добавить split, то его производительность значительно упадёт.
Вот честное сравнение slice/for http://jsbench.github.io/#35ec4a8199d42ffc7de83998f0de34f8
(странно что в Firefox кейс со slice быстрее, чем for)
There was a problem hiding this comment.
По ссылке http://jsbench.github.io/#35ec4a8199d42ffc7de83998f0de34f8 не вижу правильного варианта slice
There was a problem hiding this comment.
https://jsperf.com/bem-react-classnames вот так вижу, что вариант for + for лучше выглядит во всех проверенных браузерах (Chrome, Safari, Firefox)
There was a problem hiding this comment.
Давайте тогда на for + for остановимся. Лучше решения не вижу на данный момент. @yarastqt
No description provided.