Как использовать новую экспериментальную функцию Profiler в React

Original author: Dave Lunny
  • Translation
Вот и вышел React 16.4.0! (Прим. переводчика — эта фича была добавлена в версии 16.4.0, тогда и был написан этот пост). И в такие моменты вы понимаете, насколько вы JavaScript — гик, если следите за минорными обновлениями своего любимого фреймворка. Отлично!



Если вы читали заметки о выпуске версии 16.4, опубликованные командой React, должно быть посчитали это обновление достаточно скучным. Pointer Events выглядят заманчиво, но если честно, до этого мало что о них слышал.

Кроме того, есть багфикс для как-бы нового метода getDerivedStateFromProps (теперь он будет вызываться при каждом рендере). Я ещё недостаточно этим пользовался, поэтому для меня это обновление было не очень важным.

Затем я увидел похороненный под заголовками анонс о том, что они добавили новый экспериментальный компонент unstable_Profiler. Видя, что моя жизнь сейчас достаточно неустойчива(unstable_), я решил прочитать RFC и попробовать его.

TLDR;


Люди из команды React пытаются сделать рендеринг асинхронным. Это может затруднить определение времени отрисовки компонентов при монтировании/обновлении. Поэтому, они возятся с этим новым блестящим компонентом Profiler

Так что вы можете использовать сегодня?

Итак, если вы профи в отслеживании производительности своих реакт-приложений, это определенно станет ещё одним хорошим инструментом в вашем арсенале. Если это не про вас, можете дальше не читать и вернуться к созданию клёвых приложений.

Использование <Profiler/>


Предупреждение: возможно вам не следует использовать это в production (ну в самом деле, это же unstable_). Позже они допилят возможность профилировать и production код.

В принципе, Profiler, это компонент, который можно извлечь из пакета React по умолчанию. Поскольку у него осторожное имя с подчеркиванием, на которое многие линтеры ругаются, вы можете обойти это следующим образом:

import React, { unstable_Profiler as Profiler } from 'react';
...
const Profiler = React.unstable_Profiler;

Теперь, когда у вас есть Profiler, давайте попрофилируем компоненты! Вы можете обернуть любую часть вашего JSX дерева в Profiler чтобы посмотреть что с ней происходит. Profiler принимает функцию onRender, в которой фиксируются сведения о времени отрисовки. Вот простой пример счетчика:

import React, { unstable_Profiler as Profiler } from 'react';
class ComponentWithProfiling extends React.Component {
    state = {
        count: 0
    };
    logProfile = (id, phase, actualTime, baseTime, startTime, commitTime) => {
        console.log(`${id}'s ${phase} phase:`);
        console.log(`Actual time: ${actualTime}`);
        console.log(`Base time: ${baseTime}`);
        console.log(`Start time: ${startTime}`);
        console.log(`Commit time: ${commitTime}`);
    };
    go = direction => () => this.setState(({ count }) => ({
        count: direction === "up" ? count + 1 : count - 1
    }));
render() {
        return (
            <Profiler id="app" onRender={this.logProfile}>
                <button onClick={this.go("up")}>️</button>
                <div>The count is {this.state.count}</div>
                <button onClick={this.go("down")}></button>
            </Profiler>
        );
    }
}

Учтите, что вы должны дать id каждому фрагменту, который профилируете Как видите ниже, onRender принимает кучу интересных метрик:


7jroojkv30.codesandbox.io

Во-первых, вы можете видеть какая была фаза рендеринга (или mount или update), что можно использовать для идентификации частей кода, которые неожиданно обновляются (так же, как отличный пакет why-did-you-update, который я использовал много раз и настоятельно рекомендую).

Далее, получаем actualTime и baseTime. Они связаны с фактическим временем, которое React тратит на вычисления рендеринга; т.е. выяснение, что изменилось. Обратите внимание, что фактическое время (actual time) первоначального подключения (mount) дольше, времени обновления (update). Это потому, что при первоначальном подключении технически все «новое». В то время как при обновлении расчеты должны быть проще, поскольку, я надеюсь, компоненты в дереве обновляются только в том случае, если они действительно изменились (то есть когда изменились значения prop/states).

В больших/реальных приложениях эти данные позволят понять где shouldComponentUpdate используется некорректно или вообще не используется, места, где пропсы со ссылочными типами часто меняются или передаются новые пропсы или просто места где вы не ожидали, что обновления займут так много времени.

Последние значения, которые мы получаем в onRender — это startTime и commitTime. Это, по сути, таймштампы с момента первоначального запуска. startTime — это время с которого выбранный компонент начал выполнять расчеты для отрисовки, тогда как commitTime — время когда React фактически зафиксировал эти изменения при отрисовке.

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

Заключение


Лично для меня, этот инструмент пока не будет очень полезен. Но это одна из тех вещей, о которых хорошо знать, потому что, если я когда-нибудь столкнусь с этими узкими местами в производительности, это будет неплохим средством чтобы их измерить.

Важно сначала измерить свои проблемы с производительностью, таким образом, когда вы делаете “улучшения”, вы сможете сказать, действительно ли это улучшает ситуацию или только ухудшает. Я обнаружил, что оптимизация производительности — это одна из тех вещей, на которую можно потратить много времени. Поэтому прежде чем что-то оптимизировать., убедитесь что это реально необходимо.

Я с нетерпением жду, что команда React сделает с Profiler в будущем. Спасибо @bvaughn за добавление этой изящной функции!

От переводчика:
На данный момент (актуальная версия 16.6.0) Profiler не работает при server-side рендеринге. Feature request уже есть.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 3

    0

    Вот не совсем понятно, как это компонент использовать только в дев режиме. В проде конечному клиенту этот компонент не нужен. Хотелось бы в идеале иметь сборку с Profiler-ом и без, так сказать перфтесты. Но в текущей реализацию не понятно, как это сделать

      +2
      const Profiler = DEV? React.unstable_Profiler: React.Fragment;
      
        0
        Значит что если запускаете реакт в prod режиме, то onRender не будет вызываться и, соответственно, не будут идти данные о производительности. Падать ничего не будет, не нужно извращаться с проверкой режима.

      Only users with full accounts can post comments. Log in, please.