From 0083d3d783d5bc271ca1e19b56763cff69cc9661 Mon Sep 17 00:00:00 2001 From: Renat Rysaev Date: Sat, 23 Feb 2019 19:27:39 +0500 Subject: [PATCH] Translate Optimizing Performance. Update #2. --- content/docs/optimizing-performance.md | 44 +++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/content/docs/optimizing-performance.md b/content/docs/optimizing-performance.md index d999e8313..9de3b532c 100644 --- a/content/docs/optimizing-performance.md +++ b/content/docs/optimizing-performance.md @@ -14,7 +14,7 @@ React использует несколько умных подходов для По умолчанию в React есть много вспомогательных предупреждений, очень полезных при разработке. Тем не менее, они делают React больше и медленнее, поэтому вы обязательно должны использовать продакшен версию при деплое приложения. -Если вы не уверены в том, что процесс сборки настроен правильно, вы можете проверить это установив [React Developer Tools for Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi). Если вы посетите сайт с React в продакшен режиме, иконка будет с чёрным фоном: +Если вы не уверены в том, что процесс сборки настроен правильно, вы можете проверить это, установив [React Developer Tools for Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi). Если вы посетите сайт с React в продакшен режиме, иконка будет с чёрным фоном: React DevTools on a website with production version of React @@ -40,7 +40,7 @@ npm run build ### Однофайловые сборки {#single-file-builds} -Предлагаются готовые для продакшена версии React и React DOM в виде отдельных файлов: +Мы предлагаем готовые для продакшена версии React и React DOM в виде отдельных файлов: ```html @@ -67,7 +67,7 @@ yarn add --dev uglify-js-brunch brunch build -p ``` -Помните, что это нужно делать только для продакшен сборки. Вам не нужно использовать флаг `-p` или применять этот плагин во время разработки, потому что это скроет вспомогательные предупреждения React и сделает процесс сборки более медленным. +Помните, что это нужно делать только для продакшен сборки. Вам не нужно использовать флаг `-p` или применять этот плагин во время разработки, потому что это скроет вспомогательные предупреждения React и замедлит процесс сборки. ### Browserify {#browserify} @@ -81,7 +81,7 @@ npm install --save-dev envify uglify-js uglifyify yarn add --dev envify uglify-js uglifyify ``` -При создании продакшен сборки, убедитесь, что вы добавили эти плагины **(порядок имеет значение)**: +При создании продакшен сборки, убедитесь, что вы добавили эти пакеты для преобразования **(порядок имеет значение)**: * Плагин [`envify`](https://github.com/hughsk/envify) обеспечивает правильную среду для сборки. Сделайте его глобальным (`-g`). * Плагин [`uglifyify`](https://github.com/hughsk/uglifyify) удаляет импорты, добавленные при разработке. Сделайте его глобальным (`-g`). @@ -98,10 +98,10 @@ browserify ./index.js \ >**Примечание:** > ->Имя пакета `uglify-js`, но двоичный файл, который он предоставляет, называется `uglifyjs`.
+>Имя пакета `uglify-js`, но фактически он предоставляет исполняемый файл с именем `uglifyjs`.
>Это не опечатка. -Помните, что это нужно делать только для продакшен сборки. Вам не следует использовать эти плагины в процессе разработки, потому что это скроет вспомогательные предупреждения React и сделает процесс сборки более медленным. +Помните, что это нужно делать только для продакшен сборки. Вам не следует использовать эти плагины в процессе разработки, потому что это скроет вспомогательные предупреждения React и замедлит процесс сборки. ### Rollup {#rollup} @@ -135,7 +135,7 @@ plugins: [ Полный пример настройки можно [посмотреть здесь](https://gist.github.com/Rich-Harris/cb14f4bc0670c47d00d191565be36bf0). -Помните, что это нужно делать только для продакшен сборки. Вам не следует использовать плагин `uglify` или плагин `replace` со значением `'production'` в процессе разработки, потому что это скроет вспомогательные предупреждения React и сделает процесс сборки более медленным. +Помните, что это нужно делать только для продакшен сборки. Вам не следует использовать плагин `uglify` или плагин `replace` со значением `'production'` в процессе разработки, потому что это скроет вспомогательные предупреждения React и замедлит процесс сборки. ### webpack {#webpack} @@ -155,7 +155,7 @@ new webpack.optimize.UglifyJsPlugin() Вы можете узнать об этом больше в [документации webpack](https://webpack.js.org/guides/production-build/). -Помните, что это нужно делать только для продакшен сборки. Вам не стоит использовать `UglifyJsPlugin` или `DefinePlugin` со значением `'production'` в процессе разработки, потому что это скроет вспомогательные предупреждения React и сделает процесс сборки более медленным. +Помните, что это нужно делать только для продакшен сборки. Вам не стоит использовать `UglifyJsPlugin` или `DefinePlugin` со значением `'production'` в процессе разработки, потому что это скроет вспомогательные предупреждения React и замедлит процесс сборки. ## Анализ производительности компонентов с помощью вкладки Chrome «Performance» {#profiling-components-with-the-chrome-performance-tab} @@ -171,7 +171,7 @@ new webpack.optimize.UglifyJsPlugin() 3. Откройте в инструментах разработчика Chrome вкладку **[Performance](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/timeline-tool)** и нажмите **Record**. -4. Выполните действия, которые вы хотите анализировать на производительность. Не записывайте более 20 секунд, иначе Chrome будет зависать. +4. Выполните действия, которые вы хотите проанализировать на производительность. Не записывайте более 20 секунд, иначе Chrome может зависнуть. 5. Остановите запись. @@ -183,11 +183,11 @@ new webpack.optimize.UglifyJsPlugin() В настоящее время Chrome, Edge, и IE являются единственными браузерами поддерживающими эту функцию, но мы используем стандарт [User Timing API](https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API) поэтому ожидайте, что больше браузеров добавят эту поддержку. -## Анализ производительности компонентов с помощью инструментов разработчика Profiler {#profiling-components-with-the-devtools-profiler} +## Анализ производительности компонентов с помощью инструмента разработчика «Profiler» {#profiling-components-with-the-devtools-profiler} `react-dom` 16.5+ и `react-native` 0.57+ предоставляют расширенные возможности анализа производительности в режиме разработки с помощью инструментов разработчика React Profiler. Обзор профайлера можно найти в посте блога ["Введение в React Profiler"](/blog/2018/09/10/introducing-the-react-profiler.html). -Пошаговое видео-руководство так же [доступно на YouTube](https://www.youtube.com/watch?v=nySib7ipZdk). +Пошаговое видео-руководство также [доступно на YouTube](https://www.youtube.com/watch?v=nySib7ipZdk). Если вы ещё не установили инструменты разработчика React, вы можете найти их здесь: @@ -204,7 +204,7 @@ new webpack.optimize.UglifyJsPlugin() Если ваше приложение рендерит длинные списки данных (сотни или тысячи строк), мы рекомендуем использовать метод известный как "экранирование". Этот метод рендерит только небольшое подмножество строк в данный момент времени и может значительно сократить время, необходимое для повторного рендера компонентов, а также количество создаваемых DOM-узлов. -[react-window](https://react-window.now.sh/) и [react-virtualized](https://bvaughn.github.io/react-virtualized/) - это популярные библиотеки для экранирования. Они предоставляют несколько переиспользуемых компонентов для отображения списков, сеток и табличных данных. Если вы хотите использовать что-то более специфическое для вашего конкретного случая, то вы можете создать собственный экранируемый компонент, как это сделано в [Twitter](https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3). +[react-window](https://react-window.now.sh/) и [react-virtualized](https://bvaughn.github.io/react-virtualized/) -- это популярные библиотеки для экранирования. Они предоставляют несколько переиспользуемых компонентов для отображения списков, сеток и табличных данных. Если вы хотите использовать что-то более специфическое для вашего конкретного случая, то вы можете создать собственный экранируемый компонент, как это сделано в [Twitter](https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3). ## Избежание согласования {#avoid-reconciliation} @@ -224,11 +224,11 @@ React создает и поддерживает внутреннее предс Взаимодействуя со своей страницей, вы должны увидеть, что вокруг любых компонентов, которые были повторно отрендерены появляются цветные границы. Это позволит вам выявлять ререндеринг, который возник без необходимости. Вы можете узнать больше о возможностях инструментов разработчика React из [этого поста](https://blog.logrocket.com/make-react-fast-again-part-3-highlighting-component-updates-6119e45e6833) в блоге от [Ben Edelstein](https://blog.logrocket.com/@edelstein). -Рассмотрим этот пример: +Рассмотрим такой пример:
Пример как инструменты разработчика React подсвечивают обновления
-Обратите внимание, что когда мы вводим вторую задачу, первая так же мигает на экране при каждом нажатии клавиши. Это означает, что он ререндерится вместе с полем ввода. Иногда это называют "бесполезным" рендерингом. Мы знаем, что в этом нет необходимости, так как контент первой задачи не изменился, но React этого не знает. +Обратите внимание, что когда мы вводим вторую задачу, первая так же мигает на экране при каждом нажатии клавиши. Это означает, что она ререндерится вместе с полем ввода. Иногда это называют "бесполезным" рендерингом. Мы знаем, что в этом нет необходимости, так как контент первой задачи не изменился, но React этого не знает. Несмотря на то, что React обновляет только измененные DOM-узлы, повторный рендеринг всё же занимает некоторое время. В большинстве случаев это не проблема, но если замедление заметно, то вы можете всё ускорить, переопределив метод жизненного цикла `shouldComponentUpdate`, который вызывается перед началом процесса ререндеринга. Реализация этой функции по умолчанию возвращает `true`, указывая React выполнить обновление: @@ -244,7 +244,7 @@ shouldComponentUpdate(nextProps, nextState) { ## shouldComponentUpdate в действии {#shouldcomponentupdate-in-action} -Вот поддерево компонентов. Для каждого из них `SCU` указывает что возвратил `shouldComponentUpdate`, и `vDOMEq` указывает эквивалентны ли отрендеренные React элементы. Наконец, цвет круга указывает требуется ли согласованность компонентов или нет. +Вот поддерево компонентов. Для каждого из них `SCU` указывает что возвратил `shouldComponentUpdate`, и `vDOMEq` указывает эквивалентны ли отрендеренные React элементы. Наконец, цвет круга указывает требуется ли согласовать компонент или нет.
Дерево компонентов
@@ -252,7 +252,7 @@ shouldComponentUpdate(nextProps, nextState) { Для C1 и C3 `shouldComponentUpdate` возвратил `true`, поэтому React пришлось спуститься к листьям и проверить их. Для C6 `shouldComponentUpdate` вернул `true`, и поскольку отображаемые элементы не были эквивалентны, React должен был обновить DOM. -Последний интересный случай - C8. React должен был отрисовать этот компонент, но поскольку возвращаемые им React-элементы были равны ранее предоставленным, ему не нужно обновлять DOM. +Последний интересный случай -- C8. React должен был отрисовать этот компонент, но поскольку возвращаемые им React-элементы были равны ранее предоставленным, ему не нужно обновлять DOM. Обратите внимание, что React должен был делать изменения только для C6. Для C8 этого удалось избежать сравнением отрендеренных React-элементов, а для поддеревьев C2 и C7 даже не пришлось сравнивать элементы, так как нас выручил `shouldComponentUpdate` и `render` не был вызван. @@ -289,7 +289,7 @@ class CounterButton extends React.Component { } ``` -В этом коде `shouldComponentUpdate` - это простая проверка на наличие каких-либо изменений в `props.color` или `state.count`. Если эти значения не изменяются, то компонент не обновляется. Если ваш компонент стал более сложным, вы можете использовать аналогичный паттерн "поверхностного сравнения" между всеми полями `props` и `state`, чтобы определить должен ли обновиться компонент. Этот механизм достаточно распространён, поэтому React предоставляет вспомогательную функцию для работы с ним - просто наследуйтесь от `React.PureComponent`. Поэтому, следующий код - это более простой способ добиться того же самого эффекта: +В этом коде `shouldComponentUpdate` -- это простая проверка на наличие каких-либо изменений в `props.color` или `state.count`. Если эти значения не изменяются, то компонент не обновляется. Если ваш компонент стал более сложным, вы можете использовать аналогичный паттерн "поверхностного сравнения" между всеми полями `props` и `state`, чтобы определить должен ли обновиться компонент. Этот механизм достаточно распространён, поэтому React предоставляет вспомогательную функцию для работы с ним -- просто наследуйтесь от `React.PureComponent`. Поэтому, следующий код -- это более простой способ добиться того же самого эффекта: ```js class CounterButton extends React.PureComponent { @@ -312,7 +312,7 @@ class CounterButton extends React.PureComponent { В большинстве случаев вы можете использовать `React.PureComponent` вместо написания собственного `shouldComponentUpdate`. Он делает поверхностное сравнение, поэтому вы не можете использовать его, если пропсы и состояние могут быть изменены таким образом, что поверхностное сравнение не даст нужного результата. -Это может стать проблемой для более сложных структур данных. Для примера, вы хотите, чтобы компонент `ListOfWords` отображал список слов, разделённых через запятую, с родительским компонентом `WordAdder`, который позволяет кликнуть на кнопку, чтобы добавить слово в лист. Этот код работает *неправильно*: +Это может стать проблемой для более сложных структур данных. Например, вы хотите, чтобы компонент `ListOfWords` отображал список слов, разделённых через запятую, с родительским компонентом `WordAdder`, который позволяет кликнуть на кнопку, чтобы добавить слово в список. Этот код работает *неправильно*: ```javascript class ListOfWords extends React.PureComponent { @@ -348,11 +348,11 @@ class WordAdder extends React.Component { } ``` -Проблема в том, что `PureComponent` сделает сравнение по ссылке между старыми и новыми значениями `this.props.words`. Поскольку этот код мутирует массив `words` в методе `handleClick` компонента `WordAdder`, старые и новые значения `this.props.words` при сравнении по ссылке будут равны, даже если слова в массиве изменились. `ListOfWords` не будет обновляться, даже если он содержит новые слова, которые должны быть отрисованы. +Проблема в том, что `PureComponent` сделает сравнение по ссылке между старыми и новыми значениями `this.props.words`. Поскольку этот код мутирует массив `words` в методе `handleClick` компонента `WordAdder`, старые и новые значения `this.props.words` при сравнении по ссылке будут равны, даже если слова в массиве изменились. `ListOfWords` не будет обновляться, даже если он содержит новые слова, которые должны быть отрендерены. ## Сила иммутабельных данных {#the-power-of-not-mutating-data} -Лучший способ решения этой проблемы — избегать мутирования значений, которые вы используете как свойства или состояние. Для примера, описанный выше метод `handleClick` можно переписать с помощью `concat` следующим образом: +Лучший способ решения этой проблемы — избегать мутирования значений, которые вы используете как свойства или состояние. К примеру, описанный выше метод `handleClick` можно переписать с помощью `concat` следующим образом: ```javascript handleClick() { @@ -390,7 +390,7 @@ function updateColorMap(colormap) { `updateColorMap` теперь возвращает новый объект, вместо того, чтобы мутировать исходный. `Object.assign` входит в ES6 и требует полифила. -JavaScript предоставляет [object spread properties](https://github.com/sebmarkbage/ecmascript-rest-spread) для добавления свойств объекта, чтобы упростить его обновление без мутаций: +JavaScript рассматривает предложение добавить [object spread properties](https://github.com/sebmarkbage/ecmascript-rest-spread) для добавления свойств объекта, чтобы упростить его обновление без мутаций: ```js function updateColorMap(colormap) { @@ -402,7 +402,7 @@ function updateColorMap(colormap) { ## Использование неизменяемых структур данных {#using-immutable-data-structures} -[Immutable.js](https://github.com/facebook/immutable-js) - это ещё один способ решить эту проблему. Она предоставляет иммутабельные, персистентные коллекции, которые работают с помощью механизма "structural sharing": +[Immutable.js](https://github.com/facebook/immutable-js) -- это ещё один способ решить эту проблему. Эта библиотека предоставляет иммутабельные, персистентные коллекции, которые работают с помощью механизма "structural sharing": * *Иммутабельность*: после создания коллекции она не может быть изменена. * *Персистентность*: новые коллекции могут быть созданы из предыдущей коллекции и мутированы c помощью set. После создания новой коллекции исходная коллекция останется по-прежнему неизменной.