Comments 19
www.vuemastery.com/conferences/vueconf-us-2019/9-performance-secrets-revealed
Также keep-alive не подойдет для случая, когда один и тот же компонент используется с разными данными, по крайней мере не без костылей (до сих пор issue висит открытым, чтобы можно было использовать key в include).
Также keep-alive не подойдет для случая, когда один и тот же компонент используется с разными данными, по крайней мере не без костылей (до сих пор issue висит открытым, чтобы можно было использовать key в include).
Я честно говоря не совсем понял что имелось ввиду в статье. Дело в том, что
vue-router
по-дефолту ведет себя лениво и не пересоздает вьюхи, а реюзает их. Чтобы он пересоздавал нужно ему `key` указывать. stackoverflow.com/questions/52847979/what-is-router-view-key-route-fullpath см. ответВот простой пример:
Вы можете увидеть какие хуки жизненного цикла вызываются при переходе между маршрутами. Каждый компонент создаётся перед переходом, и разрушается после перехода.
Сравните это со вторым примером:
Здесь вы увидите, что каждый компонент создаётся перед первым переходом, но не разрушается. И не создаётся заново при повторном переходе. Компонент сохраняет своё состояние когда вы уходите на другой маршрут.
codepen.io/mbeloshitsky/pen/povLRey
Object.defineProperty(itemData, 'data', {
// Отмечаем поле как "не-реактивное"
configurable: false,
value: item
})
не проще ли воспользоваться
Object.freeze
?computed: {
arr() { return [1, 2, 3, 4, 5] },
arr2() { return this.arr.map(x => x*2) },
}
Функциональный компонент компилируется в простую функцию и не имеет локального состояния. За счет этого его производительность намного вышеА по ссылке написано всё наоборот. Вы тогда внесите ясность, типа «сейчас надо делать так, но в следующей версии всё поменяется и будет по-другому».
Каждый раз обращаясь к реактивным данным Vue запускает некоторую логику, чтобы определить как и к каким данным вы обращаетесь построить зависимости и так далее.При инициализации системы реактивности и при вызове сеттера он что-то такое делает, да. А при простом обращении почему?
Представим, что вам нужно сохранить в хранилище большой массив данныхКогда мы от добавления успели перейти к обработке? И почему обработка заблокирует интерфейс? В .Net, к примеру, я спокойно могу написать в UI-потоке что-то вроде
…
Это значит, что обработка большого массива заблокирует ваш интерфейс на всё время работы.
for (int i = 0; i < 1000000; i++) {arr[i] += i;}
и ничего нигде не заблокируется, даже не лагнёт.Также непонятно, на чём основано решение, JobQueue и requestAnimationFrame — это какие-то стандартные вещи или нет, что они делают?
Имеем похожую задачу: мы добавляем в хранилище массив очень больших объектов с кучей уровней вложенностиТут проблема относится к Vue, а не конкретно Vuex.
Что вообще за «configurable: false» и как оно работает? Гугл выдаёт feature request, который непонятно чем закончился. И код — это конечно хорошо, но ещё лучше словами пояснить, что происходит.
А по ссылке написано всё наоборот. Вы тогда внесите ясность, типа «сейчас надо делать так, но в следующей версии всё поменяется и будет по-другому».
В данный момент функциональный компонент это объект с полем рендер функции
export default {
functional: true,
render(createElement, context) {
return createElement('button', 'Click me');
}
};
В следующей версии он будет упрощен до обычной рендер-функции
const FunctionalComp = props => {
const theme = inject(themeSymbol)
return h('div', `Using theme ${theme}`)
}
Не совсем уверен, что вы имели в виду говоря "всё наоборот".
При инициализации системы реактивности и при вызове сеттера он что-то такое делает, да. А при простом обращении почему?
Как я и написал — чтобы построить дерево зависимостей. Другими словами он вызывает гетеры у реактивных свойств, и запоминает что при вычислении result
было вызвано свойство base
, а значит при изменении base
нужно повторно вычислить result
.
И почему обработка заблокирует интерфейс?
Потому что так работает JavaScript. В JavaScript нет многопоточности. Если упростить, то вся ваша вкладка работает в одном потоке. Это значит что никакие две задачи не могут исполняться параллельно. И если вы запустите какую-то долгую задачу на JS, то всё остальное будет заблокировано. Попробуйте на любой странице запустить долгий цикл, например:
for (let i = 0; i < Number.MAX_SAFE_INTEGER; i++) {}
И пока он выполняется попробуйте взаимодействовать со страницей: понажимать кнопки, ссылки, какой-нибудь слайдер попереключать.
Также непонятно, на чём основано решение, JobQueue и requestAnimationFrame — это какие-то стандартные вещи или нет, что они делают?
window.requestAnimationFrame() — MDN
splitArray — абстрактная функция которая разбивает массив на части указанного размера и возвращает массив масивов.
JobQueue — абстрактный класс, который принимает какие-то колбеки (задания), и выполняет их один за одним.
Различных реализаций в интернете масса.
Что вообще за «configurable: false» и как оно работает? Гугл выдаёт feature request, который непонятно чем закончился
Или как указали в коментариях выше, можно использовать Object.freeze()
Как я и написал — чтобы построить дерево зависимостей. Другими словами он вызывает гетеры у реактивных свойств, и запоминает что при вычислении result было вызвано свойство base, а значит при изменении base нужно повторно вычислить result.Так зачем это делать каждый раз при обращении к свойству? Ну ладно, один раз в начале построили дерево зависимостей и всё, дальше пользуемся полученными результатами.
Если упростить, то вся ваша вкладка работает в одном потоке.Так я и говорю про UI-поток (в случае с JS он же и единственный). Неужели и правда алгоритм O(n) настолько долго выполняется, что можно успеть невооружённым глазом заметить лаги? И по-прежнему непонятно, откуда взялись долгие обработки, если мы просто добавляем массив в хранилище (внутри commit наверно что-то похожее на state.items = value).
Или как указали в коментариях выше, можно использовать Object.freeze()Мне кажется, лучше тогда вообще не допускать попадания глубоких объектов в data или хранилище, а то это оборачивание костыльно выглядит (для эксперимента, попросите кого-нибудь не в теме попробовать догадаться, что тут происходит и зачем).
Ну ладно, один раз в начале построили дерево зависимостей и всё, дальше пользуемся полученными результатами.
Года три назад я, вроде бы, также пользовался такой оптимизацией на долгих вычислениях с большим количеством данных. Но эксперимент показал, что этого делать уже не нужно — console.log в фидле вызывается один раз, даже не смотря на то, что обращение к свойству происходит в цикле.
Так я и говорю про UI-поток (в случае с JS он же и единственный). Неужели и правда алгоритм O(n) настолько долго выполняется, что можно успеть невооружённым глазом заметить лаги? И по-прежнему непонятно, откуда взялись долгие обработки, если мы просто добавляем массив в хранилище (внутри commit наверно что-то похожее на state.items = value).
Дело не в алгоритме O(n). Тут логика в том, что когда мы присваиваем свойству длинный массив, все элементы которого должны быть отрисованы (а это могут быть большие и сложные объекты (например GeoJSON) с большими и сложными шаблонами), то вью сперва сравнит их по ключу (чтобы не отрисовывать то, что уже отрисовано), а вот все новые элементы синхронно начнёт добавлять в DOM. Если новых элементов массива очень много, то и отрисовка DOM-дерева для них также займёт приличное время (зависит ещё от железа, конечно). Вот пока DOM-дерево создаётся, пока браузер всё это не отрисует — это и есть время лага, вкладка браузера в этот момент просто зафризится.
Суть оптимизации в этом и состоит — разбить внесение изменений в DOM-дерево на небольшие кусочки. Да, отрисовка может получиться с рывками, но это всё-равно лучше, чем полностью фризить страницу.
Но эксперимент показал, что этого делать уже не нужно — console.log в фидле вызывается один раз, даже не смотря на то, что обращение к свойству происходит в цикле
Вы правы, Vue кэширует значения вычисляемых свойств. И при повторном обращении не вычисляет их заново.
НО! Под капотом, он всё равно выполняет некоторую логику, при каждом обращении.
Проверить это очень легко: достаточно замерить время выполнения в обоих случаях:
https://jsfiddle.net/kozack/3a78q4vj/13/
Если посмотреть в консоли, то вы увидите, что staticData
вычисляется только один раз, не смотря на многочисленные обращения. И увидите, что optimized
вычисляется приблизительно в 10 раз быстрее, благодаря тому, что обращения к staticData сведены к минимуму.
Я уже после своего комментария понял, что не то проверял)
Удивительно то, что скорость вычислений падает аж в 18-20 раз. Значит не зря я несколько лет назад что-то подобное делал.
Прям хоть правило для eslint'а пиши, чтобы оно заставляло писать что-то вроде
const { anotherComputed } = this;
в начале методов и других computed'ов, если обращение к ним просходит в циклах или методах массивов forEach/map/reduce/etc.НЛО следует удалить этот случайный комментарий
Если ваше приложение построено так, что зависит только от объекта верхнего уровня и не ссылается на реактивные данные где-то на несколько уровней ниже
Не очень понятно, как данные будут изменять в компоненте, если изменились в родителе и вы отключили реактивность?
9 советов по повышению производительности Vue