На выходных посмотрел видео Алексея Макаренкова с заголовком “Полоса загрузки - не то, чем кажется…”, где он рассказывает как разработчики игр мухлюют с полоской загрузки.
Вкратце: полоска загрузки в играх - фейк, могла двигаться как угодно, но движется рывками, человеческое восприятие считает именно такой сценарий загрузки самым правдоподобным, а в плавную загрузку игроки не верят. Лучше один раз увидеть, чем сто раз услышать, вот это видео: Полоса загрузки - не то, чем кажется... (осторожно, присутствует реклама красного банка).
Но если смотреть лень, то дальше Алексей говорит о том, что это и так было предсказуемо - секрет Полишинеля, но об этом никто, как правило, не говорит. Когда люди узнают правду, это их “слегка” удивляет. Более того, в статьях и лекциях девелоперов, даже в тех которые посвящены дизайну экранов загрузки, о фейках не пишут.
И тут я могу попытаться заполнить пробел, и рассказать про то, как создавал фейковый экран загрузки. Нет, я не разработчик игр, однако играми экраны загрузки не ограничиваются. Лично я писал такой муляж для приложения на Silverlight. Как давно, это было, помнит только мутной реки вода: все сроки давности уже прошли, про это приложение, да и про Silverlight, уже все позабыли, так что можно снять гриф секретности, сдуть пыль со старого кода и вспомнить как это было.
Олды тут? Вместо дисклеймера
В публикации будет некрокод, с учётом того, что Silverlight уже не поддерживается, буду исходить из предположения что никто разбираться в этом не желает, постараюсь давать пояснения, достаточные для формирования представления и понимания. Всё-таки статья не про Silverlight, а про то, “как разработчики обманывают с экранами загрузки”.
Проблема. Вместо введения
Нам экран загрузки изначально не особо был нужен, и уж тем более не было цели кого-то обманывать. В проекте присутствует индикатор загрузки по умолчанию, он справлялся со своей обязанностью, даже ничего писать не надо, типичный код, по-моему, генерируется при создании проекта:
aspx страница
<%@ Page Language="c#" AutoEventWireup="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Silverlight Client</title>
<style type="text/css">
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost {
height: 100%;
text-align:center;
}
</style>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript">
function redirect(url) {
window.location.href = url;
}
function onSilverlightError(sender, args) {
var appSource = "";
if (sender != null && sender != 0) {
appSource = sender.getHost().Source;
}
var errorType = args.ErrorType;
var iErrorCode = args.ErrorCode;
if (errorType == "ImageError" || errorType == "MediaError") {
return;
}
var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n";
errMsg += "Code: " + iErrorCode + " \n";
errMsg += "Category: " + errorType + " \n";
errMsg += "Message: " + args.ErrorMessage + " \n";
if (errorType == "ParserError") {
errMsg += "File: " + args.xamlFile + " \n";
errMsg += "Line: " + args.lineNumber + " \n";
errMsg += "Position: " + args.charPosition + " \n";
}
else if (errorType == "RuntimeError") {
if (args.lineNumber != 0) {
errMsg += "Line: " + args.lineNumber + " \n";
errMsg += "Position: " + args.charPosition + " \n";
}
errMsg += "MethodName: " + args.methodName + " \n";
}
throw new Error(errMsg);
}
</script>
</head>
<body>
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/MainApplication.xap"/>
<param name="windowless" value="true"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="#FFDFF0F8" />
<param name="minRuntimeVersion" value="4.0.50826.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object>
<iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px">
</iframe>
</div>
</form>
</body>
</html>
Указывается xap-файл, и пока он грузится - идёт индикатор загрузки: вращающееся колесо и число показывающее процент загрузки в зависимости от размера скачиваемого xap-файла: скачалось 2 Мб из 8, покажет 25%. Это поведение по умолчанию - ничего дополнительно писать не надо.
Всё было хорошо пока в один прекрасный день, в который никто ничего не трогал, оно само, размер скачиваемого xap-файл ни стал оцениваться в 0 байт. Само собой файл не стал невесомым, просто, почему-то, при скачивании, кто-то, или что-то, зарезал заголовок с размером файла.
На экране загрузке гордо крутилось колесо с надписью 0%, висели эти 0% относительно долго, обычно загрузка занимала пару минут, и потом резко 100%...
На поиск решения потратили день - решить с наскоку не получилось. С другой стороны жалко тратить на это время: ошибки то вроде нет, ну и что что полоска загрузки висит на нуле долгое время, - на работе приложения это не сказывается никак, да неприятно, поэтому проблему не стали сбрасывать, но решили что приоритет у неё невысокий и будет она решаться в свободное от других задач время.
Прошла неделя, периодически к этой задаче возвращались, но решение найдено не было.
Прошло ещё некоторое время. И тут начали возмущаться уже пользователи, мол висит индикатор загрузки, кэш чистили, куки чистили, компьютер перезагружали, браузер меняли, а он на нуле и ничего не грузит, и у всех такое дело. Что с приложением стало? Объясняли что так мол и так, - не надо суеты, ждите и всё будет. Пользователи набирались терпения, убедились что всё работает, но осадочек остался, и чтобы не разводить панику надо было индикатор загрузки чинить.
Вернулись к задаче, прошла ещё пара дней, а причину почему оценка размера xap-файла равна нулю, мы не нашли и даже никаких соображений на этот счёт не осталось.
В этот то момент мы и встали на скользкую дорожку. Ну самое очевидное - пользователи ведь жалуются не на то, что размер файла не определяется, а на то, что полоска загрузки замерла, на файл то им плевать с высокой колокольни.
Искушение злом. Вместо оправдания
Да, ключ к решению проблемы лежал в плоскости "вернуть правильный заголовок" и всё станет как было, но здесь мы ничего не добились. Потраченного времени жаль, - тратить его на эту “не ошибку” мы не были готовы изначально, а когда поиски не приводят к результату а приводят к ещё большей трате - так время жаль вдвойне. В итоге решили поискать решение в другой плоскости.
Мы примерно знали сколько времени занимает загрузка (замеряли), понятно что эта величина непостоянная, зависит от сети, но при типичном сценарии загрузка колебалась в районе двух минут. Соответственно нам нужно было написать экран загрузки который бы развлекал пользователей это время. На самом деле чуть больше - на всякий случай с запасом.
Реализация обмана. Вместо охоты на баг
К счастью в Silverlight задача кастомизации экрана загрузки - типичная, нацелена не на фейковые экраны, а на всякое украшательство, но так или иначе гуглится легко, а там уже кто какие цели преследует - кто украшательство, кто подделку полосы прогресса. Нужно добавить два параметра splashscreensource
и onsourcedownloadprogresschanged
:
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/MainApplication.xap"/>
<param name="splashscreensource" value="LoadScene.xaml" />
<param name="onsourcedownloadprogresschanged" value="onSourceDownloadProgressChanged" />
<param name="windowless" value="true" />
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="4.0.50826.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object>
<iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe>
</div>
Первый - это визуальное представление, xaml-файл (LoadScene.xaml
):
Второй - это скрипт для обработки загрузки.
Изначально это была просто полоска. Не знаю как так получилось, но со временем полоска, предназначенная для того чтобы заполняться равномерно в течении двух минут, превратилась в две: одна чтобы показывать общий прогресс, вторая чтобы показывать загрузку "текущего" модуля:
Откуда мы знаем какой модуль загружается и сколько времени это займёт? Да ниоткуда - это тоже подделка. Обычный массив со списком строк, которые якобы названия модулей. Названия выводятся вместо слова "загрузка".
В итоге пользователь видит что нижняя полоса - прогресс модуля, загружается достаточно быстро, вероятно это и был ожидаемый эффект: система очень быстро грузит отдельные модули, а долго загружается потому что модулей много.
Ниже представлена XAML-разметка второго варианта:
LoadScene.xaml
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0"
Source="../images/header/header-left.png"
VerticalAlignment="Top"
Stretch="None" />
<Image Grid.Row="1" Source="../images/back.png" Stretch="UniformToFill" />
<Grid Grid.Row="1" Grid.ColumnSpan="3">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MaxWidth="310"/>
<ColumnDefinition MaxWidth="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" HorizontalAlignment="Center"
Width="300" Margin="5">
<Rectangle Name="progressBarBackground"
Fill="White" Stroke="Black"
StrokeThickness="1" Height="20" Width="300" />
<Rectangle Name="progressBar" HorizontalAlignment="Left"
Fill="#FF084c7c" Height="18" Width="0" MaxWidth="298"
Margin="1,0,0,0" />
</Grid>
<Grid HorizontalAlignment="Center" Width="300"
Grid.Row="1" Grid.Column="1" Margin="5">
<Rectangle Name="progressBarBackground2"
Fill="White" Stroke="Black"
StrokeThickness="1" Height="20" Width="300" />
<Rectangle Name="progressBar2" HorizontalAlignment="Left"
Fill="#FF084c7c" Height="18" Width="0" MaxWidth="298"
Margin="1,0,0,0" />
</Grid>
<TextBlock Grid.Column="2" x:Name="LoadingText" Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MinWidth="40"
Foreground="Black" FontWeight="Normal"
FontFamily="Arial" FontSize="16" Text="0%"/>
<TextBlock Grid.Row="1" Grid.Column="2" x:Name="LoadingText2" Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MinWidth="40"
Foreground="Black" FontWeight="Normal"
FontFamily="Arial" FontSize="16" Text="0%"/>
<TextBlock Grid.Row="2" x:Name="MessageText" Margin="5"
Grid.ColumnSpan="4"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="Black" FontWeight="Normal"
FontFamily="Arial" FontSize="12" Text="Загрузка"/>
</Grid>
</Grid>
</Grid>
Здесь у нас четыре квадрата: два для верхней полосы прогресса (progressBarBackground
, progressBar
), два для нижней.
По одному квадрату progressBarBackground
и progressBarBackground2
- представляют пустую незаполненную полосу прогресса, и ещё по одному progressBar
и progressBar2
меняют свою ширину по мере “загрузки” и тем самым иллюстрирует движение полосы прогресса.
Также здесь несколько текстовых блоков для отображения числа в процентах и названия исполняемого модуля.
Собственно для реализации анимации прогресса нужно сделать изменение ширины у progressBar
и progressBar2
, ну и надписи периодически менять.
Для всего этого необходимо реализовать onSourceDownloadProgressChanged
, возвращаемся к aspx файлу:
<script type="text/javascript">
var id = 0;
var diff = ["Загрузка модуля справочников", "Загрузка модуля отображения информации", "Загрузка атрибутивных данных", "Загрузка модуля редактирования", "Формирование списка документов", "", ""];
var i = 0;
function onSourceDownloadProgressChanged(sender, eventArgs)
{
var val = sender.findName("progressBar").Width / sender.findName("progressBarBackground").Width;
if (eventArgs.progress > val)
{
sender.findName("LoadingText").Text = Math.round((eventArgs.progress * 100)) + "%";
sender.findName("progressBar").Width = eventArgs.progress * sender.findName("progressBarBackground").Width;
if (eventArgs.progress >= 1 / 4 * (i + 1) || eventArgs.progress >= 0.98) {
sender.findName("LoadingText2").Text = "100%";
sender.findName("progressBar2").Width = sender.findName("progressBarBackground2").Width;
}
}
if (id === 0)
{
sender.findName("MessageText").Text = diff[i];
id = setInterval(function() {
var rel = sender.findName("progressBar").Width / sender.findName("progressBarBackground").Width;
rel += (Math.random() * 2 + 2) / 100;
if (rel <= 0.96) {
sender.findName("LoadingText").Text = Math.round((rel * 100)) + "%";
sender.findName("progressBar").Width = rel * sender.findName("progressBarBackground").Width;
}
}, 3500);
setInterval(function ()
{
var rel1 = sender.findName("progressBar").Width / sender.findName("progressBarBackground").Width;
var rel2 = sender.findName("progressBar2").Width / sender.findName("progressBarBackground2").Width;
rel2 += (Math.random() * 2 + 2) / 100;
if (rel1 >= 0.96) {
sender.findName("progressBar2").Width = sender.findName("progressBarBackground2").Width;
sender.findName("LoadingText2").Text = "100%";
}
else if (rel2 >= 1) {
sender.findName("progressBar2").Width = 0;
sender.findName("LoadingText2").Text = "0%";
i++;
} else {
sender.findName("LoadingText2").Text = Math.round((rel2 * 100)) + "%";
sender.findName("progressBar2").Width = rel2 * sender.findName("progressBarBackground2").Width;
}
sender.findName("MessageText").Text = diff[i];
}, 500);
}
}
</script>
На что тут можно обратить внимание, во-первых: на diff
- это фейковый список загружаемых модулей, а i
- это индекс текущего загружаемого модуля.
И во-вторых: на функцию onSourceDownloadProgressChanged
, при нормальном сценарии, - если размер файла приходит корректный, она вызывается с некоторой периодичностью и в её параметрах содержится какая доля файла уже загружена, соответственно мы можем использовать это для честной визуализации. Однако в нашем случае функция вызывается всего два раза: в самом начале, когда загружено 0, и в самом конце, когда загружено 100%.
Этот код:
var val = sender.findName("progressBar").Width / sender.findName("progressBarBackground").Width;
if (eventArgs.progress > val)
{
sender.findName("LoadingText").Text = Math.round((eventArgs.progress * 100)) + "%";
sender.findName("progressBar").Width = eventArgs.progress * sender.findName("progressBarBackground").Width;
if (eventArgs.progress >= 1 / 4 * (i + 1) || eventArgs.progress >= 0.98) {
sender.findName("LoadingText2").Text = "100%";
sender.findName("progressBar2").Width = sender.findName("progressBarBackground2").Width;
}
}
Написан на всякий случай, чтобы не было накладок если ошибка с определением размера файла пропадёт так же внезапно, как и возникла.
В этом случае код должен попытаться правдоподобно скоординировать фейковый и реальный прогресс. По крайней мере чтобы это не сильно бросалось в глаза и наш обман не вскрылся.
Такого не случилось, но ожидаю что при таком стечении обстоятельств полоска будет заполняться плавно, как в фейковом алгоритме, и потом рывками, когда реальный прогресс загрузки начнёт обгонять поддельный.
Полоса загрузки модулей тоже начнёт двигаться рывками из-за условия в строках 7 - 10. Суть его в том, что если мы загрузили 25% от общего размера, то мы не должны показывать что грузится первый модуль, а писать уже про второй - с первым заканчивать. Если общий прогресс превысил 50%, то и второй модуль надо перестать грузить, показать что он загружен на 100% и переходить дальше и т.д. из расчёта 25% на модуль, - четыре модуля покажем и хватит.
Ну и если общий прогресс приближается к 100%, то и загружаемый сейчас модуль тоже должен сделать вид что полностью загружен.
На один листинг выше, в 22 строке есть условие
if (id === 0)
Сделано для тех же целей, - на случай если функция начнёт вызываться корректно. Если проверку условия не сделать - то запустится множество циклов в setInterval
и полоска загрузки будет двигаться очень быстро, дойдёт до 100% и замрёт так на пару минут.
Думаю это отличает нашу поддельную полосу загрузки от большинства других подделок: мы предусмотрели корректировку относительно реального прогресса.
Теперь о самих интервалах. Их два.
Первый:
id = setInterval(function() {
var rel = sender.findName("progressBar").Width / sender.findName("progressBarBackground").Width;
rel += (Math.random() * 2 + 2) / 100;
if (rel <= 0.96) {
sender.findName("LoadingText").Text = Math.round((rel * 100)) + "%";
sender.findName("progressBar").Width = rel * sender.findName("progressBarBackground").Width;
}
}, 3500);
Раз в 3.5 секунды изменяет общую полосу прогресса на случайную величину от 2 до 4 процентов. Замирает на 96% и делает вид что осталось совсем чуть-чуть, но он замер на какой-то тяжёлой операции, после которой сразу 100% и приложение запущено. Обычно загрузка завершилась раньше чем он доходил до 96%.
Второй:
setInterval(function ()
{
var rel1 = sender.findName("progressBar").Width / sender.findName("progressBarBackground").Width;
var rel2 = sender.findName("progressBar2").Width / sender.findName("progressBarBackground2").Width;
rel2 += (Math.random() * 2 + 2) / 100;
if (rel1 >= 0.96) {
sender.findName("progressBar2").Width = sender.findName("progressBarBackground2").Width;
sender.findName("LoadingText2").Text = "100%";
}
else if (rel2 >= 1) {
sender.findName("progressBar2").Width = 0;
sender.findName("LoadingText2").Text = "0%";
i++;
} else {
sender.findName("LoadingText2").Text = Math.round((rel2 * 100)) + "%";
sender.findName("progressBar2").Width = rel2 * sender.findName("progressBarBackground2").Width;
}
sender.findName("MessageText").Text = diff[i];
}, 500);
Второй интервал управляет полосой загрузки модуля. Если основная полоса загрузки подвисла на 96%, то делаем вид что текущий модуль загружен на 100%, но к следующую модулю не переходим, даже если в списке ещё что-то есть. Так и остаётся.
В остальных ситуациях плавно доходим до 100%, увеличиваем i
на единицу - доставая из массива “следующий модуль”, сбрасываем полосу прогресса загрузки модуля на 0, и всё сначала.
Загрузка “модуля” идёт в 7 раз быстрее “общей” загрузки, поэтому на всякий случай в массиве необходимо иметь 7 элементов, за границу массива не выйдет т.к. при достижении общего прогресса в 96% - мы перестаём инкрементировать переменную i
. Хотя сейчас мне это не кажется надёжным, лучше было бы ещё сделать дополнительную проверку на значение i
, ну да ладно.
Вот и вся реализация.
Заключение. Вместо покаяния
Таким образом мы дурим пользователя за его же деньги. И обмануть его не трудно! Он сам обманываться рад! И это не фигура речи, дословно не помню, но желание коллективного пользователя было сформулировано как-то так: “Сделайте хоть что-нибудь чтобы мы видели что приложение не зависло, и примерно представляли сколько ещё осталось ждать”.
С этой точки зрения мы достигли того чего хотел пользователь, приложение даже грузилось быстрее чем обещала полоса прогресса, как правило уже на 70-80% загрузка завершилась - приятный бонус за Ваше ожидание. Ну и никто больше не перезагружал страницу полагая что она зависла. Даже если бы она зависла на 96%, вряд ли бы кто-то нажал F5, ведь остался последний рывок и загрузка может завершиться в любой момент.
Если Вы читаете это как пользователь, не удивляйтесь что иногда полоса загрузки действительно не то чем кажется. Но я полагаю что в глубине души Вы и сами это давным-давно поняли, и даже готовы с этим мириться, и более того готовы простить нас - тех, кто подделывает экран загрузки, потому что почти всегда это ложь во благо.
Если Вы читаете это как разработчик - знайте, подделать экран загрузки это нормально, а порой необходимо.
Комментарии (104)
foxyrus
11.07.2023 17:35+43Код из прошивки роутера Netis n5
if(data.cpu == "100%"){ var cpu = Math.floor(Math.random()*30) + 50; data.cpu = cpu + "%"; }
velon Автор
11.07.2023 17:35+7Если знаете похожие примеры - пишите. Мне важно знать что я не самый злостный обманщик. А то кошки скребут на душе.
Старался забыть, а тут пришлось вспоминать не самый успешный опыт
А так хоть коллективная ответственность размывает индивидуальную вину.ImagineTables
11.07.2023 17:35+97Крайне редко тут что-то пишу, но в данном случае не смог устоять.
2000-й или 2001-й год. Весёлое время WinAPI/ATL/MFC. А также Ultimate Toolbox, BCG, CodeJock и прочих улучшайзеров. Я ещё толком не знаю C++, но изучаю его по хардкору, на примерах из Direct3D (конечно же IM, а не RM) и пишу свой 3D Studio MAX, с блэкджеком, проекционным полиэкраном, импортом 3DS, окном свойств, редактором объектов и мегафичей — ТУМАНОМ.
Приложение написано за месяц, да вот беда — оно запускается слишком быстро, и сплэш-скрин с маскотом (низкополигональным ГНОМОМ), которого нарисовал коллега, не удаётся рассмотреть. А ещё на сплэш-скрине внизу есть компонент progress bar'а, который одна из библиотек (уже не помню, Ultimate Toolbox, кажется) слямзила из новинки тех времён, браузера Netscape Navigator. (Для самых маленьких радиослушателей: по горизонтальной полоске влево-вправо ездил серый градиент, точнее, его пик насыщенности). И его тоже не удаётся рассмотреть, что обидно вдвойне.
Тогда я добавляю в Init() кучу Sleep()'ов, но вдруг вижу, что градиент перестаёт ездить, а картинка при щелчке становится белой. Еду в библиотеку, зарываюсь в книжки, и узнаю, что есть, оказывается, такая штука — МНОГОПОТОЧНОСТЬ. И если сделать Sleep() в главном потоке UI, то градиент (как и картинка) перестаёт перерисовываться.
Архитектура срочно меняется на многопоточную. Заодно в свете новых знаний движок переписывается с нуля. И вот, наконец, сплэш-скрин висит секунд десять, всё тормозит, как в лучших домах Лондона и Парижа, сразу видно — СЕРЬЁЗНЫЙ ПРОДУКТ. Но чего-то не хватает. Чего? А вот чего: экран висит, градиент ползает, а индикатор жёсткого диска не моргает! Липа, короче. Фейк.
Штош, начинаю создавать в отдельном потоке кучу файлов и писать в них rnd(). Заодно узнаю, как правильно работать с папкой tmp, с каталогами юзерского профиля, что нельзя писать в Program Files и т.д. Опять переписываю движок.
Наконец, всё готово. Экран не только тормозит, но и отчаянно трещит жёстким диском. Ну прямо Microsoft Word и Adobe Photoshop. С этим приложением я иду в одну контору, показываю его на собеседосе, и меня берут, несмотря на малый возраст, писать софт для трёхмерной визуализации месторождений. Хэппи енд.
sim2q
11.07.2023 17:35+1Приложение написано за месяц, да вот беда — оно запускается слишком быстро, и сплэш-скрин с маскотом (низкополигональным ГНОМОМ), которого нарисовал коллега, не удаётся рассмотреть.
Т.е. что бы фотошопе успеть прочитать все имена?:)
ps писал фэйковый вывод при загрузке курской PC XT совместимой машины, для чего-то было надо в офис, там ещё было смешное: При двух мегах памяти (если не ошибаюсь), писало: load memory emulator 16 Mb...
zakker
11.07.2023 17:35+10Мы делали свой прогресс бар (в одной старой игре) относительно честным. Немножко мухлевали в начале (до 15%) и в конце (после 85%). Работало это так: до 15% ползунок идет плавно в течении одной секунды. Далее честная загрузка с отображением реальных 0..100 в 15..85 на экране. Ну и с 85 до 100 тоже плавно за секунду. Даже несмотря на то, что загрузка шла на 2 секунды дольше, чем могла бы, визуально воспринималась бодрее.
Red_Nose
11.07.2023 17:35+3Я пробовал решать этот вопрос на сборе статистики (скорость исполнения конкретного отчета [sql]). Реализовал, но не внедрил :(
Да, это "детское" решение, но явно лучше полного отсутствия решения от ДБ для пользователей (у Оракла есть, но не статистика, а предрасчет).
plobov
11.07.2023 17:35Лайфакх - ставишь спиннер + отсчет времени сколько примерно осталось. Никого не обманывая, легче можно рассчитать примерное время выполнения, корректируя его на ходу, я бы так сделал)
ftc
11.07.2023 17:35+3Ага, а потом получаем прогрессбар как в старых виндах при копировании - "Осталось миллион-с-чем-то минут" и "с чем-то" постоянно уточняется.
Hlad
11.07.2023 17:35+5У меня была подобная ситуация при написании диплома в ВУЗе. Задача была переписать одну древнюю софтину, которая что-то там вычисляла. Вычисление делалось путём перемножения матриц конского размера. Считалось всё очень долго, а матрицы были очень специфические, поэтому я забурился в математику, и нашёл алгоритм вычислений, который считал их моментально. На предзащите мне предъявили, что "это фигня какая-то, раньше считало чуть ли не час, а сейчас меньше секунды, так не бывает", поэтому мне пришлось рисовать прогресс-бар, который красиво полз около минуты...
velon Автор
11.07.2023 17:35+5Думаю в контексте защиты диплома надо было понимать это так: "Сейчас зададим ему какой-нибудь вопрос и посмотрим как выкрутится. Делал сам - ответит, делал не сам или мухлевал - смутится и откажется комментировать". Ну, т.е. провокация на для того чтобы началась паника у тех кто не знает своей собственной работы.
Полагаю что их бы устроил ответ в духе: "обычно считают алгоритмом со сложностью О(n^2), но у нас есть специфика благодаря которой мы можем рассчитывать на определённые вещи и использовать алгоритм который считает за O(1)".
Тем самым Вы бы показали что разбираетесь в альтернативах, Вам понятен и вопрос и проблема и предметная область. Эмуляция прогресс бара в этом случае скорее бегство от диалога с комиссией.
Хотя комиссии и члены комиссии разные бывают, может вам не повезло и попался кто-то действительно вредный, кому вообще ничего не докажешь какие бы аргументы не привести.Hlad
11.07.2023 17:35+2Нет, там достаточно специфические преподы были, про "алгоритмы со сложностью O(n^2)" они вряд ли знали вообще.
AlanRow
11.07.2023 17:35+2Сочуствую, знающие преподаватели это важно. Мне вот с вузом повезло - преподаватели в большинстве хорошо разбирались в материале, причем не только своем. Когда я на защите начал рассказывать про дискретное преобразование Фурье (с которым не сталкивался в программе вуза и узнал только при работе над темой) меня в итоге перебили и попросили не углубляться в то, что и так всем известно)
befree
11.07.2023 17:35+9In Soviet Russia на защите не ты уходишь от неудобного диалога с комиссией, а комиссия уходит от неудобного диалога с тобой.
Ronkosa
11.07.2023 17:35+7Яркий пример, но в другой области, это телефонные гудки, созданы, чтоб пользователи понимали, что телефон работает, длинные гудки после набора номера, чтоб пользователи понимали, что надо просто ждать, а не паниковали из-за тишины
vassabi
11.07.2023 17:35+1пришлось однажды писать "второй прогрессбар" - фейковый прогрессбар, который показывал, что приложение не зависло, а просто очень медленно скачивает (это сейчас старлинк есть, а тогда через спутник оооооочень медленно байтики скачивались у некоторых денежных клиентов)
heartdevil
11.07.2023 17:35+1Давным давно делал прогрес бар для загрузки и парсинга авиабилетов с одного популярного сервиса. Зачем-то там в дизайне нарисовали прогрес бар. Я честно пытался сделать его честным), но в итоге посчитал среднее время загрузки json-а на несколько различных размеров и поставил таймер 33/66/99/~100 :)
csharpreader
11.07.2023 17:35+7Где-то именно на Хабре в комментах было: мол, в одной конторе прикрутили красивую фичу – отправляешь заявку во внутреннюю техподдержку и любуешься на прогресс-бар по срочным заявкам. В какой-то момент выяснилось, что прогресс-бар – просто картинка. Ребятам в техподдержку падала срочная заявка, и пока они её руками делали, пользователю отрисовывался красивый прогресс выполнения ))
ReinRaus
11.07.2023 17:35+22Иногда полоса загрузки или хотя бы спиннер очень нужны в приложении. Пусть даже на несколько секунд.
В приложении "Huawei Health" есть кнопка "Проверить обновление прошивки носимого устройства". Ты её тыкаешь и через доли секунды появляется результат, что уже установлена самая свежая версия ПО. Даже не верится, что там что-то проверялось. Вот если бы покрутился спиннер пару секунд, то такой результат был бы более уважительным :)
P.S. Это не шутка. Часто тыкаю кнопку "Проверить обновления" дважды из-за слишком быстрого ответа :)
AVX
11.07.2023 17:35+5Где-то писали похожее про кнопку "сохранить" в офисе или libreoffice, не помню. Типа, многие нажимают несколько раз, потому что слишком быстро сохраняется и не понятно, то ли сработало, то ли нет. Хотя вроде как сейчас обозначают и цветом значка кнопки и сообщением где-то в строке статуса, звездочкой в названии или ещë как-то.
Wesha
11.07.2023 17:35+6Типа, многие нажимают несколько раз, потому что слишком быстро сохраняется и не понятно, то ли сработало, то ли нет.
А у нормальных людей после сохранения текст на кнопке меняется на "СОХРАНЕНО!" и она становится неактивной.
AVX
11.07.2023 17:35+6В libreoffice так и есть. Если изменения документа были, то становится доступной.
P. S. Во времена дискет ещë и звуковые эффекты - жужжит, трещит, и точно понятно, что оно там сохранялось. (но копию файла сделать надо!)
SquareRootOfZero
11.07.2023 17:35+15Дык, в той же Винде, бывает, сделаешь двойной клик по ярлыку на рабочем столе — и чо-то никакой реакции не видно, и сиди, гадай: а оно запускается или чо? а может, я не докликнул? а может, оно упало уже? Подождёшь, ещё раз даблкликнешь, потом ещё. Через несколько секунд оно возникает на экране в пяти экземплярах. В каком-то линуксовом оконном мессенджере, помню, было интуитивнее: кликнул, иконка начала как-то жмыхаться туда-сюда — значит, ты, во всяком случае, всё правильно нажал.
boingo-00
11.07.2023 17:35В плазме у курсора прыгает значок приложения
В MATE на панели задач пишется "запускается AppName"
Viacheslav01
11.07.2023 17:35+3В одном очень и очень давно ученом мануале по улучшению UX приложения было написано, для улучшения отзывчивости приложения не обязательно реально улучшать отзывчивость, достаточно показать пользователю, что приложение работает, самый простой способ это прогресс бар. Ну а если нет данных о прогрессе процесса, замедление по экспоненте наш выход )
madcatdev
11.07.2023 17:35+2Самый тут простой способ - это крутящееся колесико, и ничего с заполнением мудрить не надо.
ris58h
11.07.2023 17:35+8С колёсиком работу не отличить от зависания, а вот прогрессбар, который заполняется (пусть и фальшиво) сразу успокаивает.
madcatdev
11.07.2023 17:35+2Колесико не крутится - значит все зависло.
Shavadrius
11.07.2023 17:35+5Если колесико реализовано через показ gif, то оно и будет крутится, только бесконечно)
Gummilion
11.07.2023 17:35+4Обычно за отрисовку колесика отвечает система, и даже если UI тред завис - оно будет продолжать крутиться. Чтобы было "по-честному" - надо, чтобы именно из рабочего потока периодически вызывалась функция поворота колесика на несколько градусов, но кто с таким будет заморачиваться?
mayorovp
11.07.2023 17:35Успокаивает он только до тех пор пока программа не зависнет с этим прогресс-баром.
Viacheslav01
11.07.2023 17:35+7Колесико не дает ощущения работы и какого то прогресса в ее выполнении, а прогресс бар дает.
AVX
11.07.2023 17:35+5Давным-давно, лет 19 назад, писал на vb6 программу для диплома, по обработке данных (численное вычисление магнитных полей было вроде). Так комп не особо шустрый, и вычисления занимали много часов. Пришлось почти сразу придумывать прогрессбар или два даже, иначе не видно было, движется там или повисло всë по какой-то причине. И вроде ничего, норм было. Пока не узнал что можно приоритет процесса через winapi менять, ну и поставил в высокий очень - а при нëм вычисления довольно быстрее стали, но прогрессбар уже не отрисовывал - его приоритет был ниже, и казалось, что зависает. Потом сделал крутилку для оперативного переключения приоритета прямо во время вычислений - можно было выбрать что важнее - несколько быстрее вычислить, или чаще видеть изменения прогресса. Без него проблемно прям.
А вот в mathcad'е не было прогрессбара, и когда забиваешь огромную формулу чтобы он что-то там упростил или решил уравнение в символьном виде - всë зависало, и непонятно было, сколько ждать. На некоторых задачах у меня комп жужжал часов 6. Кто-то из однокурсников говорил, что было и сутки ожидания, пока посчитает, но того стоило. Вручную все эти фурье и z-transform считать и дифференцирование-интегрирование - ну его нафиг. Вот что мешало там тоже встроить прогрессбар?
mayorovp
11.07.2023 17:35Если вычисления становятся быстрее при повышении приоритета — значит, запущена куча ненужных программ которые надо бы закрыть. Так что это не нормальное решение, а трюк из разряда выживания на свалке.
А прогрессбару (точнее, потоку UI) тоже можно приоритет менять, странно что вы этого не нашли...
AVX
11.07.2023 17:35+2Так я не программист :) Там и код не очень-то был, я подозреваю. В то время интернета-то нормального не было, диалап по карточкам, и как бы не соврать, всё ещё WinME стояла на на компе. Про закрытие программ я экспериментировал, вплоть до замены shell :-) Но на одном ядре AMD Duron 800 далеко не уедешь, как ни крути.
ElvenSailor
11.07.2023 17:35одно из двух:
1 реально некогда переключить контекст (т.е шевеление прогрессбаром замедлит обсчёт задачи) - вполне реально на железе тех времён
2 Объём задачи точно не известен, в процессе выполнения могут образоваться новые штуки, которые надо считать - т.е. хрен знает что взять за 100%. Если сделать в лоб, прогресс будет отползать назад, а люди такого не любят =)
diakin
11.07.2023 17:35В одном приложении на Дельфях прогрессбар должен был рисоваться, исходя из размера файла. Иногда функция, которая читала размер файла сбоила и возвращала -1. В результате приложение вылетало с ошибкой.
DreamingKitten
11.07.2023 17:35+16Ааааа, так вот кто пишет эти прогрессбары, которые останавливаются на 99% и висят там дольше, чем до этих 99% прогресс шёл...
masai
11.07.2023 17:35+1Насколько я помню, когда взломали шифрование файлов какой-то из первых версий Word, в программу для дешифровки добавили задержку, чтоб выглядело будто программа числа перемалывает.
Divisi0n
11.07.2023 17:35+8Проводнику Windows уже не один десяток лет, и никто даже не пытается написать ему корректный прогресс-бар...
ganzmavag
11.07.2023 17:35+3Как я понимаю, он корректный для больших и желательно однотипных файлов. То есть считает исключительно по средней скорости за последнее время и оставшемуся размеру. Как только в дело вмешиваются мелкие файлы - все, предсказать невозможно. Кстати интересно, существуют ли реальные (и не замедляющие процесс) способы сделать там реальный прогресс, учитывая разный размер файлов в очереди.
Divisi0n
11.07.2023 17:35+9Старый добрый Total Commander наличие разных/мелких файлов не смущает. А ещё эта "подготовка к копированию", которая длится дольше, чем само копирование. Вы там файлам шапочки надеваете перед походом в другую папку?
ganzmavag
11.07.2023 17:35+4Вот вспомнил Total Commander, но показалось, что там тоже были проблемы какие-то с точностью. Надо ради интереса что-нибудь мелкое в больших количествах покопировать.
Подготовка к копированию - загадочная штука, давно интересно, что они реально там готовят. Не удивлюсь, если все это время пытаются собрать данные для прогресс-бара.develmax
11.07.2023 17:35+7Там просто идет пересчет размера файлов и составления списка копирования. Так файлов может быть много и вложенных директорий много, по каждой из которых нужно получить список файлов и узнать из размер - эта операция может занимать много времени. Это необходимо как раз ради подготовки прогресс бара. Однако, можно копировать на лету без этого, но тогда будет известно время копирования и возможные проблемы (например, файл только для чтения или есть такой же файл в директории назначения).
SuhoffGV
11.07.2023 17:35+1Если файл только для чтения Total об это скажет только в процессе переноса когда дойдет до файла. На этапе подсчета не скажет.
Что сильно бесит. Поставил копироваться 100500 файлов и ушел, а он на 10м файлике встал и ждет от тебя ответа.
censor2005
11.07.2023 17:35Насколько помню, в настройках Total Commander была галочка, которая позволяла не подсчитывать время копирования, тем самым копирование ускорялось, но при этом прогресс-бар не показывал точную статистику.
SquareRootOfZero
11.07.2023 17:35+3Это юзер порядка ста лет уже подождал и ещё примерно столько же осталось?
Gummilion
11.07.2023 17:35+9Пф, всего-то сто лет... Мне как-то предложили подождать где-то под 300 миллиардов лет!
Krouler7
11.07.2023 17:35+5Зато при поиске в проводнике Windows есть та самая - фейковая загрузка, которая расположена на адресе директории. Постепенно замедляясь бежит к краю, но никогда не доходит.
Armitage1986
11.07.2023 17:35Десятая винда, прогресс-бар доходит до конца (после чего исчезает, оставляя обычную строку "Результаты поиска в ...").
roginvs
11.07.2023 17:35+1В npm есть пакет для фронтэнда который делает тоже самое, почти миллион загрузок в неделю https://www.npmjs.com/package/nprogress
Ну что делать если пользователям так больше нравится
velon Автор
11.07.2023 17:35+1Тут наверно уместнее не "нравится", а "привыкли".
Или второй вариант, я и за собой иногда такое замечают, когда оправдываю какие-то недоделки тем что и у "ООО "Майкрософт" (или подставьте любое название) так же. Ведь зачем заморачиваться, если даже ОНИ не заморочились, - значит норм.
moonster
11.07.2023 17:35+4Пришли однажды юзеры с жалобой - жмешь кнопку, говорят, и понять невозможно, что происходит, покуда операция не завершится.
Ок, мы сочинили прогресс индикатор в виде окошка, где есть горизонтальная полосочка, символизирующая процент прогресса, а так же текстовое поле с названием текущей операции.
Откуда брать процент? Насочиняли всякой сложной логики, как учитывать распараллеливаемые операции, как вложенные, что делать, если текущая операция добавит другую (дада, прогресс откатывался) и еще всякие интересные кейсы.
Юзеры довольны, разработчики - нет. Подсчет процента оказался сложным.
В один прекрасный момент я просто выбросил всю сложную логику.
Вместо нее начал считать так: от момента начала операции в течении ожидаемого максимального времени операции (эмпирическое значение, десятки секунд) процент равномерно бежит от 0 до 60, далее - каждые 10 секунд добавляется по проценту, и так до 99.
С тех пор прошел год. Никто не жаловался.
JPEGEC
11.07.2023 17:35Таким образом мы дурим пользователя за его же деньги. И обмануть его не
трудно! Он сам обманываться рад! И это не фигура речи, дословно не
помню, но желание коллективного пользователя было сформулировано как-то
так: “Сделайте хоть что-нибудь чтобы мы видели что приложение не
зависло, и примерно представляли сколько ещё осталось ждать”.Простите, а вывести таймер чем плохо? И видно что процесс не завис и обмана нет.
velon Автор
11.07.2023 17:35+4Просто таймер который показывает сколько времени прошло?
Плохо тем, что нет ощущения прогресса, то что время идёт, пользователь и так знает, но он же не это хочет знать, он хочет знать что работа идёт. С таймером это не очевидно, вполне может быть так, что работа стоит, а срок идёт.
TheScriptCompany
11.07.2023 17:35+4Вот так делают поддельные экраны загрузки, а потом пользователи удивляются, а что же это у них на ста процентах ещё на несколько десятков секунд застревает программа или игра)
velon Автор
11.07.2023 17:35+6Я и сам как пользователь этому удивляюсь. Но...
Тут всё гораздо хуже чем кажется:загрузка идёт плавно - пользователи удивляются
загрузка идёт рывками - пользователи удивляются
загрузка не идёт но приложение думает - пользователи удивляются
приложение запустилось без загрузки - пользователи удивляются
Пользователи всегда удивляются. Можно потратить много времени на честную оценку но пользователи всё равно будут удивляться.
allcreater
11.07.2023 17:35+2Это и для реальных экранов нормально, ведь экран загрузки обычно показывает прогресс по некоей конкретной, заданной разработчиками, очереди задач, а после ее окончания может проделываться еще какая-то тяжелая работа в главном потоке, из-за которого собственно все и подвисает.
Но, в отличие от поддельного, тут есть два преимущества: время подвисания более-менее фиксированное и зависит обычно только от производительности девайса, а еще это можно зарефакторить и таки сделать по-человечески =)
ieroglyph
11.07.2023 17:35+22Разрабатывали мы один проект АРМ на базе Линукс. По сути, запускалось наше ПО автоматически при старте системы в полноэкранном режиме, но начальные экраны загрузки системы были видны, что раздражало заказчика и коробило общее чувство прекрасного. Пришли к тому, что в качестве изображения silent boot поставили "лого" проекта, на экране загрузки самой системы - то же лого с названием проекта и статическое изображение прогрессбара на 4%. Затем на рабочем столе стояло то же изображение с прогрессбаром на 11%. Потом уже, когда стартовало наше приложение, начинали с того же изображения, готовности 15% и потихоньку доводили до 100% под контролем сложной логики с получением ответов о готовности разных железяк вперемежку с несколькими sleep()ами.
AVX
11.07.2023 17:35+3Мне вот как раз больше нравится, когда приложение (или ОС) честно показывает текстом, что сейчас делается, и не надо особо прогресса никакого, ну можно счётчик типа "1 из 20: запуск службы хххх", если применимо и заранее известно количество. Можно ведь и в программах так делать (и во многих делают), что если программа что-то загружает, пишет, какой файл загружается, если что-то вычисляет - что именно вычисляет (если это может быть долго). А всякие splash-screen'ы только в неведении держат. Может оно и оправдано, если нужно скрыть от пользователя внутреннее устройство (неважно что мы там делаем, вот тебе готовый результат, а пока смотри картинку).
gruzoveek
11.07.2023 17:35+4Делали внутренний продукт и там был один тяжелый запрос в БД. Ответ ехал около 40 сек после всех оптимизаций. Чтоб юзеры не думали что все подвисло, я прикрутил фейковый прогресс-бар (спиннеров тогда еще не придумали), он мелкими рандомными рывками шел к 100% в течение тех 40 секунд. Потом поменяли это дело на спиннер, медитировать на который юзерам нравилось больше. Процент "загрузки" отрисовывали внутри спиннера по тому же алгоритму, по которому двигался прогресс-бар.
wnder
11.07.2023 17:35+3Год эдак 2004, мы пишем на Дельфи 7. На нашем заводе активно внедряют юникса и делают локалку.
Мы пишем программу, которая - о чудо, локалка же! - ходит не только в промышленную сеть, но и в локалку. Установщик все подтягивает, подкачивает, настраивается, опрашивает профибас, гребет данные с серверов в соседнем здании по эзернет.Но блин - сеть иногда тупит, а сроки горят. Надо представить цеху красивую поделку на радость начальнику смены. Мы им приносим не просто программу, а программу с установщиком! (ой да это как я игрушки дома ставлю, покажите? Интересно)
В принципе все хорошо, но в двух местах программа не может четко понимать время, оставшееся до конца работы и наш прогресс бар "подвисает". Мы делаем гениальное для того времени решение - изобретаем спиннер! - делаем прогресс бар который закрашивается в обе стороны.
Устанавливаем программу на рабочем месте начальника смены - и дядька задумчиво смотрит как прогрессбар добежал до 100% и побежал к нулю. И примерно при 50% все закончилось.
Хммм... - сказал дядька
Программа установлена! - сказали мы. - Можно работать. Обновление поставится таким же способом.
Хорошо.... - сказал очень задумчивый босс цеховиков. - Мы сами сможем поставить, тут все просто...velon Автор
11.07.2023 17:35+10Если бы я увидел как прогресс бар побежал обратно, я бы испугался: "эй куда, всё же было, вернись я всё прощу"
wnder
11.07.2023 17:35+2Мы импровизировали, а заказчик задачи "завис" на стадии приемки. Но принял :)
SuperTEHb
11.07.2023 17:35+21Это вам казалось, что завис. На нём прогрессбара просто не было.
velon Автор
11.07.2023 17:35+10До чего дошёл прогресс, теперь мы можем ходить но совещания со спинером, чтобы коллеги видели что мы думаем над их вопросом, а не игнорим.
И просто на работе сидишь - крутишь спинер, значит работаешь, а не зависаешь
Gummilion
11.07.2023 17:35+9Тем более, в каком-то из стандартных установщиков (то ли InstallShield, то ли MSI) если при установке происходил сбой, прогресс реально откатывался на 0. Так что повод волноваться действительно был.
9982th
11.07.2023 17:35+1У меня такое буквально позавчера было. В Factorio при игре по сети сначала загружается статический файл сохранения, а потом подтягивается и применяется дифф событий, которые произошли на сервере за время, прошедшее с начала загрузки. Хост, ожидая пока я загружусь, подошел к месту с высокой активностью ботов, которые, судя по всему, генерировали события быстрее, чем мой клиент успевал их загружать и применять, в результате чего у меня шкала загрузки натурально поползла влево.
mayorovp
11.07.2023 17:35Это не шкала загрузки, а шкала синхронизации, она появляется уже после загрузки сохранения. И, к слову, ей не важно где хост находится, потому что ботов надо обсчитать всех на карте и быстрее чем они у хоста летают.
Grigorenkovic
11.07.2023 17:35+2Тоже была задача сделать прогресс-бар при получении данных из БД. Сделал таблицу для хранения замеров производительности в зависимости от параметров и отборов, и подставлял нужное количество секунд.
allcreater
11.07.2023 17:35+1Довродилось ковыряться в системе загрузочных задач движка одной мобильной игры, так вот у нас все было относительно честно: общий прогресс определяется количеством запланированных и завершенных задач, а так же локальным прогрессом самих задач. Те таски, которые могли (и хотели) точно сообщать о своих достижениях, сообщали, некоторые мухлевали и выдавали приблизительный результат, некоторые о прогрессе не сообщали и результат бинаризовался.
koreychenko
11.07.2023 17:35+1Прикольно делать процентные индикаторы для процессов продолжительность которых вы не знаете и которые всегда разные в зависимости от 100500 факторов.
infino1
11.07.2023 17:35+4Во времена ремонта сотовых телефонов, товарищ писал мне программу, изображающую что комп подключен к телефону, бежит полоса загрузки и потом выдает ошибки.
Клиенты стоят над головой и просят что бы сделал телефон прямо сейчас, а когда показываешь -вот смотри программа видит кучу неисправностей и за пол часа не устранить, клиент с спокойной душой оставляет телефон в ремонт.
ZvoogHub
11.07.2023 17:35-3Продвинутые юзеры знают что если пристально смотреть на полосу загрузки, то загрузка происходит немного быстрее.
Если серьёзно - какой-то блоггер почему-то решил что полоса обязательно должна означать время и двигаться равномерно.
Но обычно она показывает сколько из этапов задачи пройдено и сколько осталось. На многих экранах загрузки приложений можно видеть ещё и подпись к текущему процессу. Типа "загрузка шрифтов", "инициализация библиотеки такой-то" и т.п.
Пользователи к этому привыкли и вполне лояльно относятся.
Не надо искать проблему там где её нет.
konst90
11.07.2023 17:35+3Мне как пользователь важно знать, сколько будет выполняться задача, хотя бы примерно. Перекур? Обед? На ночь запустить?
balamutang
11.07.2023 17:35+4Мы так для одной конторы контроллер делали для сбора данных с картридеров по Wiegand, стартовал то он моментально, но чтобы прибор казался солиднее - я добавил визуальный процесс инициализации: по дисплею 16х2 две секунды полз прогрессбар. Все были в восторге.
shasoftX
11.07.2023 17:35+3Прогресс-бар делается для пользователя, чтобы тот не скучал. Поэтому не важно как он выводится, если пользователь не злится, значит всё норм.
Всегда интересно наблюдать как в кино когда ищут по отпечаткам на экран монитора выводятся фото и отпечатки проверяемого человека. При этом ты понимаешь, что в реальности это просто мишура потому что это адски тормозит процесс.
velon Автор
11.07.2023 17:35Из-за этих киноделов наверно не одно когнитивное искажение появилось. Понаснимают всякого ради красивый картинки, а пользователи потом удивляются почему программы не выглядят так как в кино, - приходится подстраиваться под ожидания.
Вот она - фабрика грёз, со всеми последствиями
Sild
11.07.2023 17:35А размеры модулей сильно менялись? Почему бы было не захардкодить размер в коде, если в заголовках пусто? Это было бы куда менее трудозатрадно
velon Автор
11.07.2023 17:35+1Если знать нужное место где надо хардкодить то да, было бы куда менее трудозатрадно и более того привычно. Но я такого места не нашёл. А тратить дальше время на поиски было не целесообразно.
Можете помотреть первоначальный код aspx страницы, я его самым первым листингом приложил. Куда там можно захардкодить!? По этой странице вообще не скажешь, что есть какая-то полоса загрузки, а она всё же была. Очевидно, что если и хардкодить размер файла, то явно не там.
Изначально планировали сделать быстро заглушку, а потом поискать ещё, но заглушка всех устроила и поиски забросили. Нет ничего более постоянного чем временное.
gluck59
11.07.2023 17:35+5Как-то раз меня с честным прогрессбаром достал главный продажник: мол чо это у тебя полоска доходит только до 90 и на этом месте все нужное уже появляется на экране? Не объяснишь ведь продажнику, что последний файл залетает быстрее его ожиданий... Пришлось добавить "процентов" прогрессбару, чтобы он успевал доползти до 100 и продажник ушел довольный.
Но тут вмешался тимлид: нафик ты это очковтирательство захардкодил, убирай! Лишние проценты пришлось отрезать, а продажника стравить с тимлидом: пусть сами разбираются.
Закончилось не помню чем, но эта задача на меня больше не падала.В следующий раз в другой задаче я не стал ориентироваться на настоящую загрузку, а поставил бутстраповский прогрессбар, который по сути ничего не показывал, а только запускал анимацию полосок на всю ширину индикатора. Этот вариант ни у кого не вызвал вопросов и ушел в прод сразу...
GnuriaN
11.07.2023 17:35Это было давно.... Был Qbasic, который поставлялся отдельно с редактором и компилятором на "Англицком" языке :-). Тестовый интерфейс программы с поддержкой мыши. "Аля драйвер" был написан на псевдокодах и грузился в память. В зависимости от мощности ПК 286, 386, 486.. Было найдено оптимальное время которое требовалось на загрузку всего (что бы мышка заработала) и был сделан экран загрузки в котором через цикл была загрузка экрана.... Это был 2000 год.... 11 класс....
Sensimilla
11.07.2023 17:35+1В некоторых играх: анимация, прогресс бары, и прокручивающиеся счетчики - это вообще основа игрового процесса, гарантия того, что пользователь не будет слишком быстро проходить игру и зарабатывать очки. И вот это вот бесит максимально.
gres_84
11.07.2023 17:35+1На одной из работ происходила проверка оборудования. Длительность ее была неизвестна, но не должна была превышать 1.5 минут. Поэтому прогресс бар просто заполнялся как текущее время от начала/1.5 минуты.
velon Автор
Если знаете похожие примеры - пишите. Мне важно знать что я не самый злостный обманщик. А то кошки скребут на душе.
Старался забыть, а тут пришлось вспоминать не самый успешный опыт
А так хоть коллективная ответственность размывает индивидуальную вину.