Поговорим об оптимизации производительности интерфейса

внешний интерфейс оптимизация производительности
Поговорим об оптимизации производительности интерфейса

предисловие

性能优化, тема, которую не может избежать каждый инженер. вот моя комбинацияMr.MaxОдин из курсов , и кратко изложены некоторые методы оптимизации, надеюсь, он будет полезен всем, и будет продолжать обновляться в будущем.Те, кто хочет посмотреть видео, могут напрямую перейти к определенному курсу в онлайн-поиске. Исходный код демо и PPT являются условно общими (一个赞👍), спасибо, ребята 😎

Первый личный блог

Лучшее время посадить дерево было десять лет назад, затем сейчас

демо

fe-оптимизировать исходный код

Презентация PPT (обязательно посмотрите, супер красавчик)

онлайн предварительный просмотр

Исходный код fe-ppt PPT, созданный с помощью HTML

Влияние на производительность внешнего интерфейса (многословное предупреждение ❗️❗️❗️)

Важным показателем производительности интерфейса является время загрузки страницы, которое зависит не только от пользовательского опыта, но и от рейтинга в поисковых системах.

  • Данные Google показывают, что страница с 10 фрагментами данных, которые можно загрузить за 0,4 секунды, превращается в 30 фрагментов данных, которые можно загрузить за 0,9 секунды, а трафик и доходы от рекламы снижаются.90%.
  • Размер файла домашней страницы Google Map от100KBсокращено до70-80KBПосле этого трафик увеличился в первую неделю10%, выросла в течение следующих трех недель25%.
  • Цифры Amazon показывают: время загрузки увеличивается100毫秒, продажи下降1%.

Итак: мой долг переосмыслить перфоманс 😎

1. Инструменты отладки

Наточите нож, не нарубив случайно дрова, а после окончания университета подработайте!

1. Сеть

Здесь вы можете увидеть детали загрузки ресурсов и изначально оценить влияние页面性能элементы. Правой кнопкой мыши можно настроить вкладку, а внизу страницы находится обзор загруженных в данный момент ресурсов.DOMContentLoadedвремя завершения рендеринга DOM,Load: время загрузки всех ресурсов на текущей странице.

Мысли: как определить, какие ресурсы бесполезны для текущей загрузки страницы, и провести соответствующую оптимизацию?

shift + cmd + P, чтобы вызвать инструмент расширения консоли и добавить правила

Расширенный инструмент Больше жестов

водопад водопад

  • QueueingБраузер поставил ресурс в очередь
  • StalledМертвое время из-за времени постановки в очередь
  • DNS LookupВремя разрешения DNS
  • Initial connectionВремя установить HTTP-соединение
  • SSLВремя, когда браузер устанавливает безопасное соединение с сервером
  • TTFBВремя ожидания возврата данных сервером
  • Content Downloadвремя загрузки браузера

2. Маяк

  • First Contentful PaintВремя рендеринга первого экрана, зеленый в течение 1 с
  • Speed IndexИндекс скорости, зеленый в течение 4 с
  • Time to Interactiveвремя до страницы с заменой

Согласно некоторым стратегиям Chrome, он автоматически оценивает качество веб-сайта и дает некоторые предложения по оптимизации.

3. Производительность

Самый профессиональный анализ сайта~ Я расскажу об этом много раз позже

4. Тест веб-страницы

Вы можете имитировать доступ в различных сценариях, таких как имитация разных браузеров, разных стран и т. д., адрес онлайн-теста:webPageTest

5. Анализ упаковки ресурсов

webpack-bundle-analyzer

npm install --save-dev webpack-bundle-analyzer
// webpack.config.js 文件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports={
  plugins: [
    new BundleAnalyzerPlugin({
          analyzerMode: 'server',
          analyzerHost: '127.0.0.1',
          analyzerPort: 8889,
          reportFilename: 'report.html',
          defaultSizes: 'parsed',
          openAnalyzer: true,
          generateStatsFile: false,
          statsFilename: 'stats.json',
          statsOptions: null,
          logLevel: 'info'
        }),
  ]
}

// package.json
"analyz": "NODE_ENV=production npm_config_report=true npm run build"

Включить исходную карту

webpack.config.js

module.exports = {
    mode: 'production',
    devtool: 'hidden-source-map',
}

package.json

"analyze": "source-map-explorer 'build/*.js'",

npm run analyze

2. ВЕБ-API

Если рабочий хочет хорошо работать, он должен сначала заточить свои инструменты. Некоторые аналитические API, предоставляемые браузерами至关重要

1. Отслеживайте статус активации окна

Вы посещали МООК в колледже? Видео остановится, как только вы отойдете от окна~

Или некоторые экзаменационные сайты, которые напоминают вам, что вы не можете выйти из текущего окна.

Или этот эффект~

// 窗口激活状态监听
let vEvent = 'visibilitychange';
if (document.webkitHidden != undefined) {
    vEvent = 'webkitvisibilitychange';
}

function visibilityChanged() {
    if (document.hidden || document.webkitHidden) {
        document.title = '客官,别走啊~'
        console.log("Web page is hidden.")
    } else {
        document.title = '客官,你又回来了呢~'
        console.log("Web page is visible.")
    }
}

document.addEventListener(vEvent, visibilityChanged, false);

На самом деле скрытых API много, вот тут можете попробовать, если интересно:

2. Наблюдайте за длинными задачами (Задача в исполнении)

const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
        console.log(entry)
    }
})

observer.observe({entryTypes: ['longtask']})

3. Отслеживайте изменения в сети

Дайте пользователям обратную связь о проблемах с сетью при изменении сети. Иногда ваша сеть зависает при просмотре прямой трансляции. Платформа прямой трансляции также напомнит вам или автоматически переключит разрешение для вас.

var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
var type = connection.effectiveType;

function updateConnectionStatus() {
  console.log("Connection type changed from " + type + " to " + connection.effectiveType);
  type = connection.effectiveType;
}

connection.addEventListener('change', updateConnectionStatus);

4. Рассчитайте время DOMContentLoaded

window.addEventListener('DOMContentLoaded', (event) => {
    let timing = performance.getEntriesByType('navigation')[0];
    console.log(timing.domInteractive);
    console.log(timing.fetchStart);
    let diff = timing.domInteractive - timing.fetchStart;
    console.log("TTI: " + diff);
})

5. Дополнительные правила расчета

DNS 解析耗时: domainLookupEnd - domainLookupStart
TCP 连接耗时: connectEnd - connectStart
SSL 安全连接耗时: connectEnd - secureConnectionStart
网络请求耗时 (TTFB): responseStart - requestStart
数据传输耗时: responseEnd - responseStart
DOM 解析耗时: domInteractive - responseEnd
资源加载耗时: loadEventStart - domContentLoadedEventEnd
First Byte时间: responseStart - domainLookupStart
白屏时间: responseEnd - fetchStart
首次可交互时间: domInteractive - fetchStart
DOM Ready 时间: domContentLoadEventEnd - fetchStart
页面完全加载时间: loadEventStart - fetchStart
http 头部大小: transferSize - encodedBodySize
重定向次数:performance.navigation.redirectCount
重定向耗时: redirectEnd - redirectStart

3. Клише, военные правила Yahoo

После заточки ножа стоит подумать о том, куда его воткнуть~ 🗡🗡🗡

Сколько правил вы знаете о военных правилах Yahoo и о каких из них вы обычно пишете? Для следующих правил мы можем сделать много работы по оптимизации

1. Уменьшите передачу файлов cookie

Передача файлов cookie расходует полосу пропускания и может:

  • Уменьшите количество файлов, хранящихся в файлах cookie.
  • Статические ресурсы не нуждаются в файлах cookie, можно использовать другие доменные имена, и файлы cookie не будут активно использоваться.

2. Избегайте чрезмерного оплавления и перерисовки

Непрерывно запускать операцию перекомпоновки страницы

  let cards = document.getElementsByClassName("MuiPaper-rounded");
  const update = (timestamp) => {
    for (let i = 0; i <cards.length; i++) {
      let top = cards[i].offsetTop;
      cards[i].style.width = ((Math.sin(cards[i].offsetTop + timestamp / 100 + 1) * 500) + 'px')
    }
    window.requestAnimationFrame(update)
  }
  update(1000);

Посмотрите на эффект, очевидно, что коробка

performanceрезультаты анализов,loadСуществует значительный обратный поток после события, иchromeотмечены красным

использоватьfastDomДля оптимизации дом读和写разделять, объединять

 let cards = document.getElementsByClassName("MuiPaper-rounded");
  const update = (timestamp) => {
    for (let i = 0; i < cards.length; i++) {
      fastdom.measure(() => {
        let top = cards[i].offsetTop;
        fastdom.mutate(() => {
          cards[i].style.width =
            Math.sin(top + timestamp / 100 + 1) * 500 + "px";
        });
      });
    }
    window.requestAnimationFrame(update)
  }
  update(1000);

Посмотрите еще раз на эффект, он очень плавный~ performanceРезультаты анализа, после события загрузки не так много красных меток

Если вам интересно, вы можете узнать о fastDom:github fastdomонлайн просмотр:fastdom demo

Мысли о разделении и объединении задач,react fiberАрхитектура очень впечатляет.Если вам интересно, вы можете узнать о практике алгоритма планирования в волокне.

4. Сжатие

Хм, убедитесь, что вы не ошиблись, и продолжайте!

1. Сжатие

Для получения информации о способе открытия см.:nginx включает gzip

Есть еще один способ: сгенерировать файлы gz во время упаковки и загрузить их на сервер, чтобы для сжатия не требовался nginx, что может снизить нагрузку на сервер. Вы можете обратиться к:Сжатые файлы gzip и конфигурация веб-пакета Compression-webpack-plugin

2. Сжатие сервера

server.js

const express = require('express');
const app = express();
const fs = require('fs');
const compression = require('compression');
const path = require('path');


app.use(compression());
app.use(express.static('build'));

app.get('*', (req,res) =>{
    res.sendFile(path.join(__dirname+'/build/index.html'));
});

const listener = app.listen(process.env.PORT || 3000, function () {
    console.log(`Listening on port ${listener.address().port}`);
});

package.json

"start": "npm run build && node server.js",

3. Сжатие JavaScript, Css, HTML

Соответствующие плагины можно использовать непосредственно в инженерных проектах.Существует три основных типа веб-пакетов:

  • UglifyJS
  • webpack-parallel-uglify-plugin
  • terser-webpack-plugin

Конкретные преимущества и недостатки см.:Три плагина сжатия JS, обычно используемые webpack.压缩原理Проще говоря, нужно удалить некоторые пробелы, переводы строк и комментарии, а также использовать функцию модуляризации es6, чтобы выполнить некоторые действия.tree-shakingОптимизация. При этом делается некоторая обфускация кода, с одной стороны, для меньшего размера, с другой стороны, для безопасности исходного кода.

Сжатие CSS — это в основном плагин mini-css-extract-plugin, конечно, предыдущий плагин сжатия js также сделает сжатие CSS за вас. Используйте позу:

npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
plugins:[
 new MiniCssExtractPlugin({
       filename: "[name].css",
       chunkFilename: "[id].css"
   })
]

можно использовать сжатие htmlHtmlWebpackPlugin, одностраничный проект имеет только один index.html, а прирост производительности минимален~

4. Сжатие заголовка http2

Особенности http2

  • Бинарное кадрирование
  • сжатие заголовка
  • управление потоком
  • мультиплексирование
  • приоритет запроса
  • пуш сервераhttp2_push: 'xxx.jpg'

Конкретный метод обновления также очень прост, измените конфигурацию nginx, сделайте это самостоятельно.Google

Пять, оптимизация веб-пакета

Некоторые плагины для веб-пакетов также упомянуты выше, позвольте мне посмотреть, что еще есть~

1. DllPlugin повышает скорость сборки

пройти черезDllPluginПлагины, разделите несколько относительно больших пакетов, которые редко обновляются, и создайтеxx.dll.jsфайл, черезmanifest.jsonЦитировать

webpack.dll.config.js

const path = require("path");
const webpack = require("webpack");
module.exports = {
    mode: "production",
    entry: {
        react: ["react", "react-dom"],
    },
    output: {
        filename: "[name].dll.js",
        path: path.resolve(__dirname, "dll"),
        library: "[name]"
    },
    plugins: [
        new webpack.DllPlugin({
            name: "[name]",
            path: path.resolve(__dirname, "dll/[name].manifest.json")
        })
    ]
};

package.json

"scripts": {
    "dll-build": "NODE_ENV=production webpack --config webpack.dll.config.js",
  },

2, распаковка разделенных фрагментов

optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    name: 'vendor',
                    test: /[\\/]node_modules[\\/]/,
                    minSize: 0,
                    minChunks: 1,
                    priority: 10,
                    chunks: 'initial'
                },
                common: {
                    name: 'common',
                    test: /[\\/]src[\\/]/,
                    chunks: 'all',
                    minSize: 0,
                    minChunks: 2
                }
            }
        }
    },

6. Скелетный экран

Используйте CSS, чтобы заранее занять хорошую позицию, а ее можно заполнить при загрузке ресурса, уменьшив перекомпоновку и перерисовку страницы, и в то же время предоставив пользователю самую прямую обратную связь. Плагины, использованные на рисунке:react-placeholder

Есть много способов реализовать каркасный экран, используяPuppeteerМного рендеринга на стороне сервера

Используйте псевдоклассы css:Решение каркасного экрана, которое можно реализовать только с помощью css

и т.д

7. Работа с окнами

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

В картинке использованы плагины:react-window

Установить:npm i react-window

Вводить:import { FixedSizeList as List } from 'react-window';

использовать:

const Row = ({ index, style }) => (
  <div style={style}>Row {index}</div>
);
 
const Example = () => (
  <List
    height={150}
    itemCount={1000}
    itemSize={35}
    width={300}
  >
    {Row}
  </List>
);

8. Кэш

1. HTTP-кеш

keep-alive

Чтобы определить, открывать ли: см.response headersЕсть лиConnection: keep-alive. После открытия см.networkне в водопадеInitial connectionкропотливый

nginx устанавливает keep-alive (открыт по умолчанию)

# 0 为关闭
#keepalive_timeout 0;
# 65s无连接 关闭
keepalive_timeout 65;
# 连接数,达到100断开
keepalive_requests 100;

Cache-Control / Expires / Max-Age

Установите, кэшируется ли ресурс, и время кэширования

Etag / If-None-Match

Сравнивается уникальный идентификатор ресурса, и если есть изменения, ресурс извлекается с сервера. Если изменений нет, ресурс кеша занят, а код состояния равен 304, то есть кэш согласования

Last-Modified / If-Modified-Since

Сравнивая разницу во времени, чтобы решить, следует ли получать ресурсы с сервера

Для получения дополнительных параметров кэша HTTP см.:Использование кэширования HTTP: Etag, Last-Modified и Cache-Control

2. Сервисный работник

С помощью плагина webpackWorkboxWebpackPluginиManifestPlugin, загрузить serviceWorker.js, передатьserviceWorker.register()регистр

new WorkboxWebpackPlugin.GenerateSW({
    clientsClaim: true,
    exclude: [/\.map$/, /asset-manifest\.json$/],
    importWorkboxFrom: 'cdn',
    navigateFallback: paths.publicUrlOrPath + 'index.html',
    navigateFallbackBlacklist: [
        new RegExp('^/_'),
        new RegExp('/[^/?]+\\.[^/]+$'),
    ],
}),

new ManifestPlugin({
    fileName: 'asset-manifest.json',
    publicPath: paths.publicUrlOrPath,
    generate: (seed, files, entrypoints) => {
        const manifestFiles = files.reduce((manifest, file) => {
            manifest[file.name] = file.path;
            return manifest;
        }, seed);
        const entrypointFiles = entrypoints.app.filter(
            fileName => !fileName.endsWith('.map')
        );

        return {
            files: manifestFiles,
            entrypoints: entrypointFiles,
        };
    },
}),

Девять, предварительная загрузка и отложенная загрузка

1. Предварительная загрузка

В качестве примера возьмем шрифт в демо, нормальный порядок загрузки следующий:

加入preload:

<link rel="preload" href="https://fonts.gstatic.com/s/longcang/v5/LYjAdGP8kkgoTec8zkRgqHAtXN-dRp6ohF_hzzTtOcBgYoCKmPpHHEBiM6LIGv3EnKLjtw.119.woff2" as="font" crossorigin="anonymous"/> 
<link rel="preload" href="https://fonts.gstatic.com/s/longcang/v5/LYjAdGP8kkgoTec8zkRgqHAtXN-dRp6ohF_hzzTtOcBgYoCKmPpHHEBiM6LIGv3EnKLjtw.118.woff2" as="font" crossorigin="anonymous"/> 
<link rel="preload" href="https://fonts.gstatic.com/s/longcang/v5/LYjAdGP8kkgoTec8zkRgqHAtXN-dRp6ohF_hzzTtOcBgYoCKmPpHHEBiM6LIGv3EnKLjtw.116.woff2" as="font" crossorigin="anonymous"/> 

2. Предварительная выборка

Сценарий: первой странице не нужен такой файл шрифта, следующей странице нужен: первая страница будет загружена заранее с самым низким приоритетом Самый низкий

加入prefetch:

<link rel="prefetch" href="https://fonts.gstatic.com/s/longcang/v5/LYjAdGP8kkgoTec8zkRgqHAtXN-dRp6ohF_hzzTtOcBgYoCKmPpHHEBiM6LIGv3EnKLjtw.113.woff2" as="font"/> 
<link rel="prefetch" href="https://fonts.gstatic.com/s/longcang/v5/LYjAdGP8kkgoTec8zkRgqHAtXN-dRp6ohF_hzzTtOcBgYoCKmPpHHEBiM6LIGv3EnKLjtw.118.woff2" as="font"/> 
<link rel="prefetch" href="https://fonts.gstatic.com/s/longcang/v5/LYjAdGP8kkgoTec8zkRgqHAtXN-dRp6ohF_hzzTtOcBgYoCKmPpHHEBiM6LIGv3EnKLjtw.117.woff2" as="font"/> 

нужная страница, изprefetch cacheПринимать

webpack также поддерживает эти два свойства:webpackPrefetch и webpackPreload

3. Ленивая загрузка

рисунок

机械图片

渐进式图片(类似高斯模糊)Этот формат необходимо указать при публикации Miss UI.

响应式图片

Основной режим:<img src="./img/index.jpg" sizes="100vw" srcset="./img/dog.jpg 800w, ./img/index.jpg 1200w"/>

Отложенная загрузка маршрута

Реализуется функцией + импорт

const Page404 = () => import(/* webpackChunkName: "error" */'@views/errorPage/404');

10. ssr && реакция-щелчок

  • Рендеринг SSR на стороне сервера, vue использует nuxt.js, react использует next.js
  • react-snap может использовать Puppeteer для рендеринга сначала одной страницы, затем сохранять DOM и отправлять его клиенту

11. Оптимизация опыта

загрузка белого экрана

loading.htmlВам нужно забрать его самостоятельно, есть другой способ, используйтеwebpackплагинHtmlWebpackPluginВставьте загрузочный ресурс на страницу

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Loading</title>
    <style>
      body {
        margin: 0;
      }
      #loadding {
        position: fixed;
        top: 0;
        bottom: 0;
        display: flex;
        width: 100%;
        align-items: center;
        justify-content: center;
      }
      #loadding > span {
        display: inline-block;
        width: 8px;
        height: 100%;
        margin-right: 5px;
        border-radius: 4px;
        -webkit-animation: load 1.04s ease infinite;
        animation: load 1.04s ease infinite;
      }
      @keyframes load {
        0%,
        100% {
          height: 40px;
          background: #98beff;
        }
        50% {
          height: 60px;
          margin-top: -20px;
          background: #3e7fee;
        }
      }
    </style>
  </head>

  <body>
    <div id="loadding">
      <span></span>
      <span style="animation-delay: 0.13s"></span>
      <span style="animation-delay: 0.26s"></span>
      <span style="animation-delay: 0.39s"></span>
      <span style="animation-delay: 0.52s"></span>
    </div>
  </body>
  <script>
    window.addEventListener("DOMContentLoaded", () => {
      const $loadding = document.getElementById("loadding");
      if (!$loadding) {
        return;
      }
      $loadding.style.display = "none";
      $loadding.parentNode.removeChild($loadding);
    });
  </script>
</html>

Небольшое объявление о приеме на работу

  • 微医集团больничная группа поддержки
  • Координаты: Ханчжоу, Чжэцзян
  • Социальный рекрутинг 3 года + или 21 стажировка
  • Электронная почта резюме:wujj@wedoctor.com

Больше оптимизаций производительности, следите за обновлениями~

Долго учился + организовывал такие Братья и сестры проходя мимо ставьте пожалуйста лайк👍, а если есть вопросы то можете оставить сообщение для обмена 😝

Справочная статья: