TL; DR; Я не обращал внимания на фронтенд-разработку, пока я не начал читать о некоторых его продвинутых концепциях и проблемах, я узнал больше об оптимизации рендеринга браузера, производительности веб-сайтов и веб-доступности. В этой статье я поделюсь некоторыми заметками, которые я сделал при изучении оптимизации рендеринга в браузере.

Я думал, что фронтенд-разработка - это только создание красивых пользовательских интерфейсов, отзывчивых и удобных для мобильных устройств веб-сайтов, которые быстро загружаются. Я представил, что Front-end разработчик - это тот, кто знает больше HTML-тегов, свойств CSS и знает, как манипулировать DOM с помощью jQuery и / или без него, и который знает, как все должно выглядеть и ощущаться при использовании его приложений, и что фронтенд-разработчик - всего лишь творческий человек, умеющий конвертировать макеты в HTML и CSS, работающий с React, Angular и Vue.js. И что backend-разработчик - это умный разработчик, который делает большие вещи в любом веб-приложении, этот - для меня - который отвечает за сложную часть, работая с базой данных, вводом-выводом файлов, аутентификацией, безопасностью и производительностью ...

По-видимому, работа с HTML, CSS и JavaScript и разработка пользовательских интерфейсов не так интересны, как создание бэкэндов и решение «реальных проблем», так почему же компании вкладывают средства в набор фронтенд-разработчиков для «простого проектирования интерфейсов»? Почему фронтенд-разработка - это отдельная и хорошо оплачиваемая специальность? В поисках ответа я начал свое путешествие по чтению и изучению статей и уроков «Продвинутая интерфейсная разработка», чтобы узнать, каково это быть фронтенд-разработчиком, и каковы их / наши проблемы, и почему есть люди, специализирующиеся на в этом.

На этой неделе я буду читать и делать заметки о том, что я узнал, если это покажется вам сложным, скучным или запутанным, это будет ответ на мои вопросы, он объяснит, почему существуют фронтенд-разработчики, люди, которым небезразлично все это и, возможно, даже больше!

Путешествие будет проходить по Руководству разработчика FrontEnd 2018. Итак, приступим к изучению интерфейсной разработки.

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

Кажется, это сложно, Здорово!
Приступим.

Производительность веб-сайта

Плохая работа убивает хорошие сайты - Пол Льюис на ud860

Как работают браузеры

Мы не можем оптимизировать или работать над производительностью веб-сайтов, не зная, как работают браузеры, отображающие их пользовательский интерфейс.

Итак, давайте заглянем под капот.

Веб-браузеры состоят из UI, движка браузера, который передает действия между UI и движком рендеринга, движка рендеринга, который отображает HTML и CSS после его анализа. В браузерах также есть уровень хранения данных, где данные хранятся локально в виде файлов cookie, localStorage, а также IndexedDB, WebsSQL и FileSystem. Также есть сеть (где обрабатываются HTTP, DNS…), интерпретатор JS и бэкэнд пользовательского интерфейса.

Дерево рендеринга

Механизмы браузера анализируют HTML и CSS, создают модель DOM, вычисляют стили и отображают веб-страницу после создания нескольких слоев.

После синтаксического анализа HTML браузер начинает создавать дерево рендеринга, оно похоже на дерево DOM без элемента ‹head›, без скрытых элементов с помощью `display: none` и с псевдоэлементами CSS, добавленными в дерево, например

h1::before {
 content: "Hello Africa";
}

Построит узел, подобный узлам DOM. После этого шага CSS будет добавлен вместе с медиа, веб-страница будет состоять из нескольких слоев.

Подробнее читайте на:

Оптимизировать рендеринг в браузере

Понимание того, как работают браузеры, заключалось в том, чтобы научиться Как оптимизировать процесс рендеринга и создавать веб-сайты, которые загружаются и работают плавно. Чтобы углубить свои знания и перейти к практическому курсу, я начал курс Оптимизация браузера Udacity, где я понял больше основных концепций рендеринга в браузере. Теперь перейдем к процессу рендеринга.

60 кадров в секунду и частота обновления устройства

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

HTML, CSS и JavaScript обрабатываются браузерами, большинство устройств, на которых работают эти браузеры, обновляют свои экраны 60 раз в секунду (это означает, что у нас 60 кадров в секунду или один кадр на 16,6666 мс). Все наши анимации должны быть менее 10 мс (источник: Разработчики Google: Производительность рендеринга).

Для этого мы должны больше знать о конвейере Pixel.

  • JavaScript большую часть времени JS используется для внесения визуальных изменений на наши веб-страницы, путем добавления элементов DOM на наши страницы, изменения стилей…
  • Расчет стиля - это процесс вычисления правил CSS, которые нужно применить к какому элементу, на основе совпадающих селекторов.
  • Макет - это процесс вычисления пробелов, ширины элемента <body> и ширины его дочерних элементов.
  • Рисование - это процесс заливки пикселей путем рисования текста, цветов, изображений, теней и каждой визуальной части каждого элемента. Рисование выполняется на нескольких слоях.

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

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

Эта часть научила меня, что некоторые задачи дороже других, некоторые свойства CSS, такие как изменение положения определенного элемента, могут вызывать вычисления стилей, расчеты макета, рисование и составные процессы, а это дорого. Хотя изменение свойства cursor не повлияет ни на макет, ни на рисование, оно будет выполняться потоком композитора с помощью графического процессора.

Производительность - это искусство избегать работы и делать любую работу максимально эффективной. - Разработчики Google: производительность рендеринга

Всю эту удивительную информацию я узнаю из ресурсов:

RAIL (ответ, анимация, бездействие, загрузка)

RAIL - это модель производительности, цели и рекомендации RAIL помогают нам обеспечить хороший UX.

В курсе Udacity учителя предложили эти показатели.

Пользователи не любят, когда анимация не плавная: 60 кадров отображается каждую секунду, анимация должна быть с частотой 16 мс на кадр. Когда дело доходит до ответа, пользователи хотят чувствовать, что результаты сразу же, любая задержка между действием и реакцией недопустима.

Это правда, что для мобильных пользователей, особенно тех, которые используют медленное соединение 3G, реалистичная цель - загрузить страницы за 5000 мс, но они соглашаются ждать, пока сайты не ответят на их ввод, а не загрузятся. Поэтому важно загружать как можно меньше данных, чтобы пользователь начал использовать страницу при полной загрузке дополнительных загрузок.

Мы также можем загружать сложные анимации заранее (подробнее о F irst L ast I nvert P Lay)

В конце этого пункта я хотел бы поделиться с вами этими полезными ссылками от Google Developers: RAIL Tools.

JavaScript: узнайте, как это работает в браузере, а затем оптимизируйте!

Механизмы JavaScript в веб-браузерах интерпретируют JavaScript с помощью JIT-компиляторов для преобразования JS-кода в байт-код.

Каждый движок JavaScript реализует версию ECMAScript, диалект JavaScript, поэтому у нас разные браузеры для поддержки ES6, ES7…

Целью процесса синтаксического анализа и выполнения кода движка JavaScript является создание наиболее оптимизированного кода в кратчайшие сроки. - Джен Лупер, Руководство по движкам JavaScript для идиотов

Код JavaScript нельзя было оптимизировать, взломав «микрооптимизации» JIT-компиляторов.

Итак, чтобы оптимизировать JavaScript, мы должны сделать многое, одна из них - запускать JavaScript как можно раньше в начале каждого кадра (вот почему мы обсудили конвейер пикселей и RAIL).

Современные браузеры предоставляют requestAnimationFrame функцию, которая планирует запуск JavaScript как можно раньше в начале кадра.

Кроме того, когда дело доходит до оптимизации JavaScript, веб-воркеры будут нашими друзьями, они позволяют нам запускать JavaScript в совершенно другом потоке, они могут выполнять ввод-вывод, не мешая основному потоку браузера, веб-воркеры могут общаться с основной код JavaScript (который его создал) сообщениями. Подробнее см. Документация по Web Worker на MDN.

Например, мы передадим строку воркеру в workerFile.js, и воркер вернет сообщение основному скрипту.

Основной сценарий:

var worker = new Worker('workerFile.js');

worker.addEventListener('message', function(e) {
  console.log('Worker said: ', e.data);
}, false);

worker.postMessage('Hello World'); // Send data to our worker.

И workerFile.js (рабочий):

self.addEventListener('message', function(e) {
  self.postMessage(e.data.toUpperCase);
}, false);

Пример взят из HTML5Rocks: основы Web worker.

Говоря об управлении памятью в JavaScript, мы можем полагаться только на сборщик мусора JavaScript. В JavaScript нет функций управления памятью или указателей, таких как malloc() и free(), поэтому в этом case Области действия переменных и вызовы функций. Например:

При объявлении локальной переменной внутри функции выделенное пространство для этой переменной будет освобождено после ее использования.

function foo(arg) {
    var bar = "this is a local variable";
}

Но при случайном использовании глобальных переменных мы все время будем использовать пространство памяти.

function foo(arg) {
    bar = "this is a hidden global variable";
}

Другой способ, при котором глобальные переменные могут быть случайно созданы через this , когда функция вызывается в глобальной области, например:

function foo() {
    this.variable = "potential accidental global";
}

// Foo called on its own, this points to the global object (window)
// rather than being undefined.
foo();
console.log(variable); // will return "potential accidental global" and not undefined

Этот пример взят из статьи форума auth0.

Также иногда при выполнении анимации и при работе с таймерами и обратными вызовами, например setInterval используется для выполнения определенной временной анимации, тогда в этом нет необходимости, давайте проверим этот пример:

var clientCountElement = document.getElementById('visitors');
var ourClients = getData(); // returns 100 for example
var clientCounter = 0;
setInterval(function() {
  if (ourClients > clientCounter) {
    clientCounter++;
    clientCountElement.innerHTML = String(clientCounter);
  }
}, 10);

Когда clientCounter достигнет ourClients , анимация остановится, количество посетителей не будет увеличиваться, но обратный вызов продолжит выполнение. Таким образом, таймеры, такие как setTimeout и setInterval, должны быть очищены после завершения желаемого действия. В моем примере я пробовал это:

var clientCountElement = document.getElementById('visitors');
var ourClients = getData(); // returned 100
var clientCounter = 0;
var animation = setInterval(function() {
      if (ourClients > clientCounter) {
        clientCounter++;
        clientCountElement.innerHTML = String(clientCounter);
      } else {
        // Here we cleanup after finishing our animation
        clearInterval(animation);
        delete animation;
      }
    }, 10);

И это создало разницу, как в этом предварительном просмотре с использованием Диспетчера задач Google Chrome.

Таймеры также могут вызвать другую проблему, они могут работать в конце кадра, поэтому это может привести к пропуску кадра.

Итак, решение для этого - UsingrequestAnimationFrame. Как в этом примере от Google developers:

/**
 * If run as a requestAnimationFrame callback, this
 * will be run at the start of the frame.
 */
function updateScreen(time) {
  // Make visual updates here.
}

requestAnimationFrame(updateScreen);

Другая утечка памяти - это ссылки вне DOM, например, при сохранении узла ячейки таблицы (<td>), а затем при удалении узла таблицы из DOM по некоторым причинам. Таблица будет удалена из DOM, но останется в памяти, ячейка таблицы является дочерним узлом <table>, а дочерние элементы сохранят ссылки на своих родителей, поэтому ссылка на ячейку таблицы заставляет всю таблицу оставаться в памяти.

Источники:

Оптимизация CSS тоже имеет значение!

При оптимизации наших веб-страниц мы также должны позаботиться о CSS. Рекомендуется использовать методологию BEM (Block Element Modifier), она проще, многоразовая и оптимальна. Браузерам проще вычислять классы CSS, чем вычислять nth-child(n), это кажется логичным: сопоставление элемента происходит быстрее, чем вычисление Какой это элемент? чем совпадение с этим вычисленным результатом.

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

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

Например, это:

// Read.
var width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = width + 'px';
  }
}

Оптимальнее, чем

function resizeAllParagraphsToMatchBlockWidth() {

  // Puts the browser into a read-write-read-write cycle.
  for (var i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = box.offsetWidth + 'px';
  }
}

Источники:

Сначала измерьте, а затем оптимизируйте

Google Chrome и Firefox предоставляют мощные инструменты для тестирования, отладки и измерения. В курсе Udacity (под названием Оружие уничтожения мусора) я немного научился измерять производительность. Firefox также предоставляет мощный инструмент измерения производительности в DevTools.

Работая над производительностью веб-сайта, мы всегда должны измерять, с самого начала и после внесения каких-либо изменений, мы не должны «пытаться решить проблемы, которых у нас нет».

Как-то, отдыхая от писательства, я зашел в Facebook, где обнаружил, что freeCodeCamp опубликовал этот замечательный доклад!

Какое красивое совпадение! Я очень рекомендую это выступление!

Здесь заканчиваются мои первые выходные, и я этому научился. Я действительно не знаю, «Каково быть фронтенд-разработчиком», как работают профессиональные фронтенд-разработчики и действительно ли им это небезразлично? Я действительно хочу услышать что-нибудь от вас, особенно от фронтенд-разработчиков!

Мне понравилось учиться на этой неделе, я понял процесс рендеринга и то, что все имеет значение. Некоторые концепции казалось труднее понять, поэтому я заинтересовался, мне нужно было больше ресурсов, чтобы понять их. Попытка делать заметки о том, что я узнаю из этой статьи, вынудила меня приложить больше усилий, чтобы понять все, что мне нужно написать, и мне нужно было написать все интересное, что я читал, поэтому письмо было для меня мотивацией!