задний план
Недавно я выполнял коллекцию и анализ веб-характеристик, и я всегда чувствовал, что коллекция, которая не имеет ничего общего с взаимодействием пользователя, помещена вonLoadилиDOMContentLoadedочень неразумно.
После некоторых поисков я обнаружил, что у веб-страниц тоже есть жизненный цикл. Некоторые исследования разрешили путаницу в том, как избежать вмешательства в сбор информации пользователем.
Последняя спецификация W3CPage Lifecycle,
Предоставляется ряд функций-ловушек жизненного цикла, чтобы разработчики могли отслеживать и обрабатывать некоторые операции, не мешая взаимодействию с пользователем.
Вопрос: Как использовать жизненный цикл для изящной обработки и составления отчетов по данным анализа, которые могут не только гарантировать отсутствие отсутствующих отчетов в определенных сценариях, но и как можно меньше мешать пользователям?
резюме
Жизненный цикл приложения — это ключевой способ, с помощью которого современные операционные системы управляют ресурсами. На мобильных устройствах iOS, Android и новейших настольных системах
Приложения могут быть запущены или закрыты операционной системой в любое время, а жизненный цикл делает эти системыstreamline(Оптимизировано для увеличения производительности и экономии), более разумно и эффективно перераспределяйте ресурсы и значительно оптимизируйте взаимодействие с пользователем.
Исторически, в Интернете не имели концепции жизненного цикла, что привело к веб-приложениям, которые всегда могут выжить и заниматься системными ресурсами. Браузер открывает большое количество страниц вкладок, Критические системы системные ресурсы, такие как память, CPU, аккумулятор и сеть, переполняются и не могут быть освобождены, в результате чего система зависает. Например, более старые версии хрома, хотя В то время он всегда был лидером в сравнении о исполнении одностранических страниц браузеров, но оно открыл слишком много страниц, особенно память. Благодаря жизненному циклу память может быть переработана разумно.
На веб-платформе уже давно есть события, связанные с состояниями жизненного цикла, такие какload,unload,visibilitychange,
Эти события позволяют разработчикам отслеживать изменения в состоянии жизненного цикла. Для мобильных устройств, особенно для некоторых недорогих моделей, браузерам нужен способ активного освобождения и перераспределения памяти.
На самом деле, современные браузеры предприняли агрессивные шаги для экономии ресурсов на фоновых вкладках, и многие браузеры хотят сделать больше, чтобы уменьшить объем своих ресурсов.
Проблема в том, что разработчики в настоящее время не имеют возможности подготовиться к такого рода вмешательствам при загрузке системы или даже знать, что они происходят. Это означает, что браузеры должны быть консервативными, иначе они рискуют сломать веб-страницы.
Page Lifecycle APIПопытайтесь решить эти проблемы следующим образом:
- Внедрение и стандартизация концепции статуса жизненного цикла в Интернете.
- Определяет новое состояние запуска системы, которое позволяет браузеру ограничивать ресурсы, доступные скрытым или неактивным вкладкам.
- Создавайте новые API и события, которые позволяют веб-разработчикам реагировать на переходы между этими новыми состояниями запуска системы.
Решение обеспечивает предсказуемость, необходимую веб-разработчикам для создания приложений, устойчивых к вмешательству в систему, и позволяет браузерам более агрессивно оптимизировать системные ресурсы, что в конечном итоге приносит пользу всем веб-пользователям.
В этой статье будут представлены новые функции жизненного цикла страницы и рассмотрена их связь со всеми существующими состояниями и событиями веб-платформы. В нем также будут даны советы и рекомендации по типам работы, которую разработчики должны (и не должны) выполнять в каждом штате.
Состояния и события жизненного цикла
Все состояния жизненного цикла страницы являются дискретными и взаимоисключающими, то есть страница может находиться только в одном состоянии в каждый момент времени. Большинство изменений состояния жизненного цикла страницы обычно можно наблюдать через события DOM (исключения см. в рекомендациях разработчика для каждого состояния).
Переходы состояний жизненного цикла и инициированные события
условие
| условие | описывать | возможное предыдущее состояние (инициирующее событие) | возможное следующее состояние (инициирующее событие) |
|---|---|---|---|
| Active | страница виднаdocument.visibilityState === 'visible'и имеютinput focus |
1. passive (focus) | 1. passive (blur) |
| Passive | Страница видна, и никакой ввод не находится в фокусе | 1. active (blur) 2. hidden (visibilitychange) |
1. active (focus) 2. hidden (visibilitychange) |
| Hidden | страница не виднаdocument.visibilityState === 'hidden'и не замороженный |
1. passive (visibilitychange) | 1. passive (the visibilitychange) 2. frozen (freeze) 3. terminated (pagehide) |
| Frozen |
frozenБраузер состояния приостанавливает выполнение замораживаемых задач в очереди задач, что означает, что, например.JS timerилиfetchОбратный вызов не будет выполнен. Текущая задача может быть завершена, но операции, которые могут быть выполнены, и время, в течение которого она может выполняться, ограничены.Заморозка браузера предназначена для экономии процессора, памяти и энергопотребления. Также ускоряет перемотку вперед и назад, избегая полной перезагрузки страницы из сети. |
1. hidden (freeze) | 1. active (resume -> pageshow) 2. passive (resume -> pageshow) 3. hidden (resume) |
| Terminated |
terminatedСтатус указывает на то, что браузер выгрузил страницу и восстановил использование ресурсов, новые задачи выполняться не будут, а длительные задачи могут быть удалены. |
1. hidden (pagehide) | без |
| Discarded |
discardedСостояние возникает, когда системные ресурсы ограничены, и браузер будет активно выгружать страницу, чтобы высвободить ресурсы, такие как память, для новых записей/потоков. В этом состоянии не могут быть выполнены никакие задачи, обратные вызовы событий или любой вид JS. Хотя страница исчезла, имя вкладки и значок страницы вкладки браузера по-прежнему видны пользователю. |
1. frozen (no events fired) | без |
мероприятие
Ниже описаны все события, связанные с жизненным циклом, и перечислены состояния, в которые они могут перейти.
focus
- Описание: Дом-элемент усиления фокусировки
- предыдущее возможное состояние
- passive
- текущее возможное состояние
- active
- Примечание. Событие фокуса не всегда вызывает изменение состояния жизненного цикла, это происходит только в том случае, если страница ранее не была в фокусе.
blur
- Описание: элемент DOM теряет фокус
- предыдущее возможное состояние
- active
- текущее возможное состояние
- passive
- Примечание. Событие размытия не всегда вызывает изменение состояния жизненного цикла, оно изменяется только тогда, когда страница больше не находится в фокусе. Например, переключение фокуса между элементами страницы не будет.
visibilitychange
- описывать:
document.visibilityStateменяется значение. Триггерная сцена:
- Обновить или перейти на новую страницу
- Перейти на новую вкладку
- Закрыть вкладку, свернуть или закрыть браузер
- Переключение приложений на мобильном терминале, например, нажатие кнопки «Домой», нажатие переключателя уведомлений на голове и т. д.
- предыдущее возможное состояние
- passive
- hidden
- текущее возможное состояние
- passive
- hidden
freeze *
- Описание: Страница заморожена, и ни одна из задач, которые можно заморозить в очереди задач, не будет выполнена.
- предыдущее возможное состояние
- hidden
- текущее возможное состояние
- frozen
resume *
- Описание: Браузер перезапустил зависшую страницу
- предыдущее возможное состояние
- frozen
- текущее возможное состояние
- active (if followed by the pageshow event)
- passive (if followed by the pageshow event)
- hidden
pageshow
- Описание: узнать, существует ли кеш навигации по страницам, если он существует, он будет взят из кеша, в противном случае будет загружена совершенно новая страница.
Свойство события, если страница была получена из кэша навигации
persistedистинно, иначе ложно. - предыдущее возможное состояние
- заморожено (событие возобновления также сработает в это время)
- текущее возможное состояние
- active
- passive
- hidden
pagehide
- Описание: Можно ли сохранить сеанс страницы в кэше навигации. Если пользователь переходит на другую страницу, и браузер может добавить текущую страницу в кеш навигации по страницам для последующего повторного использования.
, то атрибут события
persistedправда. Если это правда, страница перейдет наfrozenСостояние, иначе он войдетterminatedусловие. - предыдущее возможное состояние
- hidden
- текущее возможное состояние
- frozen (event.persisted is true, freeze event follows)
- terminated (event.persisted is false, unload event follows)
beforeunload
- Описание: Текущая страница будет выгружена. В этот момент содержимое документа текущей страницы все еще видно, и на этом этапе закрытие страницы можно отменить.
- предыдущее возможное состояние
- hidden
- текущее возможное состояние
- terminated
- Предупреждение: прослушивание
beforeunloadСобытие используется только для напоминания пользователю о несохраненных изменениях данных.После сохранения данных обратный вызов события прослушивателя должен быть удален. Его не следует добавлять на страницу безоговорочно, поскольку в некоторых случаях это может снизить производительность.
unload
- Описание: Страница выгружается.
- предыдущее возможное состояние
- hidden
- текущее возможное состояние
- terminated
- Предупреждение: мониторинг не рекомендуется
unloadсобытие, поскольку оно ненадежно, в некоторых случаях может повлиять на производительность.
- Представляет новое событие, определенное жизненным циклом.
новые особенности
замороженные и отброшенные — это системное поведение, а не активное поведение пользователя.Современные браузеры невидимы для вкладок и могут активно замораживать или удалять текущую страницу. Разработчик не может знать, как это произошло.
Chrome 68+ обеспечивает события замораживания, возобновления, когда страница переходит из скрытого состояния в замороженное и незамерзающее состояние, разработчики могут прослушиватьdocumentнаучился.
document.addEventListener('freeze', (event) => {
// The page is now frozen.
});
document.addEventListener('resume', (event) => {
// The page has been unfrozen.
});
и обеспечиваетdocument.wasDiscardedсвойство, чтобы получить текущую загруженную страницу, независимо от того, была ли она удалена, когда она не была видна ранее.
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
Код следит за состоянием жизненного цикла
Получатьactive,passive,hidden
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
картинаfrozenа такжеterminatedСостояние нужно контролироватьfreeze,pagehideприобретение события.
// Stores the initial state using the `getState()` function (defined above).
let state = getState();
// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
const prevState = state;
if (nextState !== prevState) {
console.log(`State change: ${prevState} >>> ${nextState}`);
state = nextState;
}
};
// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
window.addEventListener(type, () => logStateChange(getState()), {capture: true});
});
// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
// In the freeze event, the next state is always frozen.
logStateChange('frozen');
}, {capture: true});
window.addEventListener('pagehide', (event) => {
if (event.persisted) {
// If the event's persisted property is `true` the page is about
// to enter the page navigation cache, which is also in the frozen state.
logStateChange('frozen');
} else {
// If the event's persisted property is not `true` the page is
// about to be unloaded.
logStateChange('terminated');
}
}, {capture: true});
Приведенный выше код делает три вещи:
-
getState()инициализированное состояние - определение
logStateChangeФункция получает следующее состояние, консоль, если оно изменяется - монитор
捕获阶段мероприятие, один звонокlogStateChange, входящие изменения состояния.
Примечание. Порядок, в котором консоль печатает выше, может не совпадать в разных браузерах.
- Почему пройти в третьем параметре
{capture: true}и все вwindowотслеживать событие
- Не все события жизненного цикла одинаковы
target-
pagehide,pageshowсуществуетwindowтриггер на -
visibilitychange,freeze,resumeсуществуетdocumentтриггер на -
focus,blurСрабатывает на соответствующем элементе DOM
-
- Большинство событий не всплывают, а это означает, что во время фазы всплытия только слушатель
windowне могу достичь - Фаза захвата происходит в целевой фазе и фазе всплытия, что означает, что события фазы захвата не отменяются другими событиями всплытия.
Кроссбраузерная совместимость
Поскольку API жизненного цикла был представлен только что, новые события и API DOM реализованы не во всех браузерах. Кроме того, все реализации браузеров несовместимы. Например:
- Некоторые браузеры не срабатывают при переключении вкладок
blurсобытие означаетactiveстатус не проходитpassiveгосударство сразу становитсяhidden - Некоторые браузеры реализуют
page navigation cache,Page Lifecycle APIКлассифицировать кешированные страницы как замороженные, Но еще нетfreeze,resumeи т. д. последний API, хотя не/замороженное состояние также может быть передано черезpageshow,pagehideСобытие прослушивается. - Не реализовано в IE 10 и ниже
pagehideмероприятие -
pagehide,visibilitychangeВызыватьизмененный. Когда страница выгружается, если страница видна, она сработает первой.pagehideзапускvisibilitychange. Последняя версия Chrome срабатывает первой независимо от того, видна страница или нет.visibilitychangeзапускpagehide. - Safari закрытие вкладки может не срабатывать
pagehideилиvisibilitychange. нужно следитьbeforeunloadбыть совместимым,beforeunloadНеобходимо завершить фазу всплытия, чтобы узнать, изменилось ли состояниеhidden, поэтому его легко отменить другими событиями.
Рекомендуемое использованиеPageLifecycle.js, гарантируя согласованность между браузерами.
Рекомендации для каждого штата
Как разработчик, важно понимать состояния жизненного цикла страницы и знать, как наблюдать за ними в коде, потому что тип работы, которую вы должны (и не должны) выполнять, сильно зависит от того, в каком состоянии находится ваша страница.
Например, если страница находится в невидимом состоянии, явно не имеет смысла показывать пользователю временное уведомление. Хотя этот пример очевиден, есть и менее очевидные предложения, которые стоит перечислить.
| условие | предложение |
|---|---|
| Active | Это состояние является самым важным этапом для пользователя, где важнее всего реагировать на пользовательский ввод. Задачи без пользовательского интерфейса, которые блокируют основной поток на долгое время, могут быть переданыidleпериод илиweb workerиметь дело с |
| Passive | В этом состоянии пользователь не взаимодействовал со страницей, но все еще может ее видеть. Это означает, что обновления пользовательского интерфейса и анимация по-прежнему должны быть плавными, но время появления этих обновлений менее критично. когда страница начинается сactiveсталиpassiveэто хорошее время для хранения несохраненных данных. |
| Hidden | когдаpassiveВhidden, есть большая вероятность, что пользователь больше не будет взаимодействовать со страницей, пока она не будет перезагружена.hiddenСостояние часто является последним состоянием, которому разработчики могут доверять, особенно на мобильных устройствах, например при переключении приложений.beforeunload,pagehideа такжеunloadНи одно событие не срабатывает.Это означает, что для разработчиков следует поставить hiddenСостояние считается конечным состоянием сеанса страницы. В это время несохраненные данные приложения должны быть сохранены, а данные анализа должны быть собраны и представлены.В то же время вы должны остановить обновления пользовательского интерфейса, потому что пользователи больше не могут его видеть. Также пришло время остановить задачи, которые пользователь не хочет выполнять в фоновом режиме, экономя ресурсы, такие как электроэнергия. |
| Frozen | существуетfrozenусловие,очередь задачсерединаЗамораживаемые задачибудет приостановлено до тех пор, пока страница не будет разморожена (возможно, никогда, например, страница будет удаленаdiscarded).В этот момент необходимо остановить все timerи закрыть соединение (IndexedDB,BroadcastChannel,WebRTC,Web Socketсвязи. освобожденWeb Locks), не должны влиять на другие открытые страницы того же происхождения или браузер для сохранения страницы в кэше навигации по страницам.Вы также должны сохранять динамическую информацию о представлении (например, позицию прокрутки списка бесконечной прокрутки), чтобыsessionStorageИли IndexedDB через commit() для повторного использования после сброса и перезагрузки. когда состояние меняется обратно hiddenВы можете повторно открыть любые закрытые подключения или перезапустить любой опрос, который был остановлен, когда страница была первоначально заморожена. |
| Terminated | когда страница становитсяterminatedСтатус, разработчикам вообще ничего делать не нужно. Поскольку, когда пользователь активно выгружает страницу,terminatedопытный преждеhiddenСтатус (не обязательно срабатывает, когда страница обновляется и переходитvisibilitychange, небольшое количество браузеров реализует его, большинству может потребоватьсяpagehideчетноеbeforeunloadилиunloadчтобы компенсировать эти сценарии), вы должныhiddenСостояние выполняет завершающую логику сеанса страницы (постоянное хранение, отчетность по данным анализа).Разработчики должны осознавать, что во многих случаях (особенно на мобильных устройствах) состояние завершения невозможно надежно определить, и поэтому они полагаются на события завершения (например, beforeunload,pagehideа такжеunload) может потерять данные. |
| Discarded | Разработчики не могут наблюдать устаревшие состояния. Потому что он обычно сбрасывается, когда системные ресурсы ограничены, в большинстве случаев просто для того, чтобы скрипт мог ответитьdiscardНевозможно разморозить страницу в случае события. Поэтому нет необходимостиhiddenизменить наfrozenПри обработке можно проверить, когда страница загружаетсяdocument.wasDiscarded, чтобы восстановить ранее удаленные страницы. |
Избегайте использования старых API жизненного цикла
- выгружать, не использовать в современных браузерах
- Многие разработчики будут
unloadСобытия используются, чтобы сигнализировать об окончании страницы, чтобы сохранить состояние или сообщить аналитические данные, но это очень ненадежно, особенно на мобильных устройствах.unloadНе запускается во многих типичных ситуациях удаления, например при переключении вкладок мобильного устройства, закрытии страницы или системного переключателя, закрытии приложения. - Поэтому лучше полагаться на
visibilitychangeсобытие, чтобы определить, когда сеанс страницы заканчивается, и будетhiddenСчитается, что последнее сохраненное состояние приложений и пользовательских данных является надежным временем. -
unloadЭто предотвратит сохранение страницы браузером в кеше (кэш навигации по страницам), что повлияет на быстрый отклик браузера вперед и назад. - В современных браузерах (включая IE11) рекомендуется использовать
pagehideсобытие вместоonloadОтслеживание выгрузки страницы (прекращено).onloadВ основном совместим с IE10.
const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';
addEventListener(terminationEvent, (event) => {
// Note: if the browser is able to cache the page, `event.persisted`
// is `true`, and the state is frozen rather than terminated.
}, {capture: true});
- beforeunload, который имеет аналогичную проблему с выгрузкой, используется только для напоминания пользователю о наличии несохраненных данных при закрытии или переходе на страницу.После сохранения он будет немедленно очищен.
// bad:无条件使用
addEventListener('beforeunload', (event) => {
// A function that returns `true` if the page has unsaved changes.
if (pageHasUnsavedChanges()) {
event.preventDefault();
return event.returnValue = 'Are you sure you want to exit?';
}
}, {capture: true});
// good
const beforeUnloadListener = (event) => {
event.preventDefault();
return event.returnValue = 'Are you sure you want to exit?';
};
const unsavedChanges = [];
/**
* @param {Symbol|Object} id A unique symbol or object identifying the
*. pending state. This ID is required when removing the state later.
*/
function addUnsavedChanges(id) {
if(unsavedChanges.indexOf(id) > -1) return; // 重复退出
if (unsavedChanges.length === 0) { // 首次监听
addEventListener('beforeunload', onbeforeunload);
}
unsavedChanges.push(id);
}
/**
* @param {Symbol|Object} id A unique symbol or object identifying the
*. pending state. This ID is required when removing the state later.
*/
function removeUnsavedChanges(id) {
const idIndex = unsavedChanges.indexOf(id);
if (idIndex > -1) {
unsavedChanges.splice(idIndex, 1);
// If there's no more pending state, remove the event listener.
if (unsavedChanges.length === 0) {
removeEventListener('beforeunload', onbeforeunload);
}
}
}
FAQs
- Когда страница скрыта, выполняются важные задачи. Как предотвратить зависание или удаление страницы?
Есть много веских причин не замораживать страницу в скрытом состоянии, например, приложение играет музыку.
Существует также риск того, что браузер покинет страницу в некоторых случаях, например, когда пользователь не отправил ввод или разработчик прослушиваетbeforeunloadсобытия для оповещения пользователей.
В результате политики браузера имеют тенденцию быть консервативными, удаляя страницы только тогда, когда ясно, что это не повлияет на пользователя. Например, в следующем сценарии страница не будет удалена (если только она не ограничена ресурсами устройства).
- Playing audio
- Using WebRTC
- Updating the table title or favicon
- Showing alerts
- Sending push notifications
Примечание. Для страниц, которые обновляют заголовок или значок значка, чтобы предупредить пользователя о непрочитанных уведомлениях, рекомендуется использоватьservice worker, что позволит Chrome заморозить или удалить страницу, но по-прежнему будет показывать изменения в заголовке вкладки или значке.
- Что такое кеш навигации по страницам?
Кэш навигации по страницам — это общий термин, используемый для оптимизации навигации с помощью кнопок «назад» и «вперед», используя кеш для быстрого восстановления первых и последних страниц. Вебкит говоритPage Cache,FirefoxсказатьBack-Forwards Cache(бфкэш).
Замораживание предназначено для экономии ЦП/батареи/памяти, а кеш-память предназначена для быстрого восстановления при перегрузке, и они работают вместе, дополняя друг друга. Поэтому кеш считается частью замороженного состояния жизненного цикла.
Уведомление:beforeunload,unloadпредотвратит эту оптимизацию.
- Почему в жизненном цикле нет событий load и DOMContentLoaded?
Состояния жизненного цикла страницы определяются как дискретные и взаимоисключающие. Поскольку страница может бытьactive,passiveилиhiddenсостояние загружено, поэтому отдельное состояние загрузки не имеет смысла,
и из-заloadа такжеDOMContentLoadedСобытия не представляют изменения состояния жизненного цикла, поэтому они не имеют ничего общего с жизненным циклом.
- Как замороженное или завершенное состояние работает с асинхронными запросами
В этих двух состояниях задачи могут быть приостановлены и не выполнены, например, асинхронные запросы, API-интерфейсы на основе обратного вызова и т. д. не будут выполняться. Вот несколько предложений
- sessionStorage, этот метод является синхронным и может по-прежнему сохранять данные в заброшенном состоянии.
- работник службы, в
terminated,discardedсостояние, слушаяfreezeorpagehideпройти черезpostMessage()Используется для сохранения данных. (Ограниченные и приборные ресурсы, могут вызвать сервисный работник увеличит бремя на устройстве) - Функция navigator.sendBeacon по-прежнему может отправлять асинхронные запросы, когда страница закрыта.
- Как проверить статус замороженной и удаленной страницы?chrome://discards
Вдохновение для выбора времени сбора аналитических данных
Анализ совместимости
- избегать в
load,DOMContentLoaded,beforeunload,unloadОбработка и отчетность собранных данных. - монитор
visibilitychangeОбрабатывайте собранную информацию при переключении между приложениями и экранами. - монитор
pagehideСтраница коллекции обновляет сцену перехода навигации. - просто используйте
beforeunloadсовместимыйSafariЗакройте вкладку и сцены ниже IE11. - Обратите внимание, что после сбора информации все события сбора немедленно уничтожаются, чтобы избежать повторных отчетов.
function clear(fn) {
['visibilitychange', 'pagehide', 'beforeunload']
.forEach(event => window.removeEventListener(event, fn, true));
}
function collect() {
const data = { /* */ };
const str = JSON.stringify(data);
if('sendBeacon' in window.navigator) {
if( window.navigator.sendBeacon(url, str) ) {
clear(collect);
} else {
// 异步发请求失败
}
} else {
// todo 同步 ajax
clear(collect);
}
}
const isSafari = typeof safari === 'object' && safari.pushNotification;
const isIE10 = !('onpagehide' in window);
window.addEventListener('visibilitychange', collect, true);
!isIE10 && window.addEventListener('pagehide', collect, true);
if(isSafari || isIE10) {
window.addEventListener('beforeunload', collect, true);
}
Суммировать
Для разработчиков, стремящихся к максимальной производительности, при разработке следует учитывать жизненный цикл страницы. Для пользователей очень важно не потреблять ресурсы устройства, когда они не нужны.
Кроме того, чем больше разработчиков начинают использовать API жизненного цикла, тем безопаснее браузер будет справляться с замораживанием или удалением страниц, которые больше не используются. Это означает, что браузер будет потреблять меньше памяти, ЦП, мощности и сетевых ресурсов, что принесет пользу пользователю.