Первоначально опубликовано в Блоге Exact Realty 12 января 2023 г.

Прогрессивное улучшение

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

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

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

Рендеринг на стороне сервера и рендеринг на стороне клиента

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

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

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

Например, типичное приложение React может иметь такой HTML-код:

С соответствующей логикой рендеринга в basic.js, которая могла бы выглядеть так:

Этот простой пример покажет страницу с текстом Hello, World!.

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

Ситуации с пустой страницей в некоторых браузерах можно избежать, используя рендеринг на стороне сервера. В зависимости от рассматриваемого фреймворка подход может быть разным. Для React это можно сделать с помощью ReactDOMServer. Следуя принципам прогрессивного улучшения, рендеринг на стороне сервера должен использоваться всякий раз, когда это возможно или целесообразно, чтобы дать пользователям возможность использовать нашу страницу и взаимодействовать с ней. Преимущество этого подхода заключается в том, что сценарии на стороне клиента все еще могут использоваться для повышения интерактивности и функциональности, если клиент поддерживает это. Однако рендеринг на стороне сервера не всегда может быть жизнеспособным вариантом, в зависимости от того, для чего предназначена наша страница. Например, многофункциональное многофункциональное приложение, такое как онлайн-редактор изображений или игра, может потребовать написания сценариев для обеспечения адекватного опыта, выходящего за рамки возможностей статически сгенерированного документа.

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

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

Мы могли бы использовать <noscript> для отображения такого сообщения:

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

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

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

Например, наш обработчик ошибок может выглядеть примерно так:

Для соответствующего тела HTML с элементами error и loading:

Таким образом, браузеры без сценариев на стороне клиента будут отображать сообщение в элементе <noscript>, в то время как браузеры со сценариями будут отображать сообщение «загрузка», указывающее, что приложение еще не готово (в качестве альтернативы, это может быть содержимое страницы при использовании элемента server-). боковой рендеринг) или сообщение об ошибке в случае возникновения какой-либо ошибки.

Как правило, <script> элементов блокируют рендеринг. Это означает, что страница не будет интерактивной и не будет отображать содержимое до тех пор, пока не будут загружены скрипты. В зависимости от таких факторов, как скорость сети, это может привести к ухудшению взаимодействия с пользователем, поскольку страница будет отображаться медленно без индикации того, что происходит.

HTML5 представил атрибуты async и defer для тега <script> для решения этой проблемы. Атрибут async указывает, что сценарий должен быть загружен параллельно и выполнен, как только его содержимое будет доступно. Атрибут defer аналогичен, за исключением того, что он указывает, что сценарий должен выполняться сразу после анализа документа, но до того, как будет запущено событие DOMContentLoaded.

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

Мы могли бы использовать такую ​​вспомогательную функцию в элементе <script defer>:

Собираем все вместе

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

Во-первых, мы настраиваем HTML-документ:

Далее следует сценарий app.js:

Первоначально опубликовано в Блоге Exact Realty 12 января 2023 г.