На выходных посмотрел видео Алексея Макаренкова с заголовком “Полоса загрузки - не то, чем кажется…”, где он рассказывает как разработчики игр мухлюют с полоской загрузки.

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

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

И тут я могу попытаться заполнить пробел, и рассказать про то, как создавал фейковый экран загрузки. Нет, я не разработчик игр, однако играми экраны загрузки не ограничиваются. Лично я писал такой муляж для приложения на 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)


  1. velon Автор
    11.07.2023 17:35
    +7

    Если знаете похожие примеры - пишите. Мне важно знать что я не самый злостный обманщик. А то кошки скребут на душе.

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

    А так хоть коллективная ответственность размывает индивидуальную вину.


  1. Javian
    11.07.2023 17:35
    +13

    Экран загрузки придает приложению солидности в глазах пользователя.


    1. velon Автор
      11.07.2023 17:35
      +4

      Согласен, театр начинается с вешалки, а приложения с экрана загрузки


    1. aaa_bbb
      11.07.2023 17:35
      +1

      еще на курсовиках делал экран загрузки, подражая 97му офису ))

      по факту был вывод картинки и разного текста под ней через sleep'ы


  1. foxyrus
    11.07.2023 17:35
    +43

    Код из прошивки роутера Netis n5

    if(data.cpu == "100%"){
    		var cpu = Math.floor(Math.random()*30) + 50;
    		data.cpu = cpu + "%";
    }


  1. velon Автор
    11.07.2023 17:35
    +7

    Если знаете похожие примеры - пишите. Мне важно знать что я не самый злостный обманщик. А то кошки скребут на душе.

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

    А так хоть коллективная ответственность размывает индивидуальную вину.


    1. 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. С этим приложением я иду в одну контору, показываю его на собеседосе, и меня берут, несмотря на малый возраст, писать софт для трёхмерной визуализации месторождений. Хэппи енд.


      1. velon Автор
        11.07.2023 17:35
        +10

        Drake


      1. sim2q
        11.07.2023 17:35
        +1

        Приложение написано за месяц, да вот беда — оно запускается слишком быстро, и сплэш-скрин с маскотом (низкополигональным ГНОМОМ), которого нарисовал коллега, не удаётся рассмотреть.

        Т.е. что бы фотошопе успеть прочитать все имена?:)
        ps писал фэйковый вывод при загрузке курской PC XT совместимой машины, для чего-то было надо в офис, там ещё было смешное: При двух мегах памяти (если не ошибаюсь), писало: load memory emulator 16 Mb...


    1. zakker
      11.07.2023 17:35
      +10

      Мы делали свой прогресс бар (в одной старой игре) относительно честным. Немножко мухлевали в начале (до 15%) и в конце (после 85%). Работало это так: до 15% ползунок идет плавно в течении одной секунды. Далее честная загрузка с отображением реальных 0..100 в 15..85 на экране. Ну и с 85 до 100 тоже плавно за секунду. Даже несмотря на то, что загрузка шла на 2 секунды дольше, чем могла бы, визуально воспринималась бодрее.


    1. Red_Nose
      11.07.2023 17:35
      +3

      Я пробовал решать этот вопрос на сборе статистики (скорость исполнения конкретного отчета [sql]). Реализовал, но не внедрил :(
      Да, это "детское" решение, но явно лучше полного отсутствия решения от ДБ для пользователей (у Оракла есть, но не статистика, а предрасчет).


    1. plobov
      11.07.2023 17:35

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


      1. ftc
        11.07.2023 17:35
        +3

        Ага, а потом получаем прогрессбар как в старых виндах при копировании - "Осталось миллион-с-чем-то минут" и "с чем-то" постоянно уточняется.


        1. usernameak
          11.07.2023 17:35
          +1

          как в старых виндах

          да оно вроде всё ещё так...


        1. ElvenSailor
          11.07.2023 17:35
          +1

          самый прикол, когда время отрицательное)


    1. Hlad
      11.07.2023 17:35
      +5

      У меня была подобная ситуация при написании диплома в ВУЗе. Задача была переписать одну древнюю софтину, которая что-то там вычисляла. Вычисление делалось путём перемножения матриц конского размера. Считалось всё очень долго, а матрицы были очень специфические, поэтому я забурился в математику, и нашёл алгоритм вычислений, который считал их моментально. На предзащите мне предъявили, что "это фигня какая-то, раньше считало чуть ли не час, а сейчас меньше секунды, так не бывает", поэтому мне пришлось рисовать прогресс-бар, который красиво полз около минуты...


      1. velon Автор
        11.07.2023 17:35
        +5

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

        Полагаю что их бы устроил ответ в духе: "обычно считают алгоритмом со сложностью О(n^2), но у нас есть специфика благодаря которой мы можем рассчитывать на определённые вещи и использовать алгоритм который считает за O(1)".

        Тем самым Вы бы показали что разбираетесь в альтернативах, Вам понятен и вопрос и проблема и предметная область. Эмуляция прогресс бара в этом случае скорее бегство от диалога с комиссией.

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


        1. Hlad
          11.07.2023 17:35
          +2

          Нет, там достаточно специфические преподы были, про "алгоритмы со сложностью O(n^2)" они вряд ли знали вообще.


          1. AlanRow
            11.07.2023 17:35
            +2

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


            1. befree
              11.07.2023 17:35
              +9

              In Soviet Russia на защите не ты уходишь от неудобного диалога с комиссией, а комиссия уходит от неудобного диалога с тобой.


    1. Ronkosa
      11.07.2023 17:35
      +7

      Яркий пример, но в другой области, это телефонные гудки, созданы, чтоб пользователи понимали, что телефон работает, длинные гудки после набора номера, чтоб пользователи понимали, что надо просто ждать, а не паниковали из-за тишины


    1. vassabi
      11.07.2023 17:35
      +1

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


      1. mayorovp
        11.07.2023 17:35
        +1

        А можно было бы просто выводить скорость загрузки...


    1. heartdevil
      11.07.2023 17:35
      +1

      Давным давно делал прогрес бар для загрузки и парсинга авиабилетов с одного популярного сервиса. Зачем-то там в дизайне нарисовали прогрес бар. Я честно пытался сделать его честным), но в итоге посчитал среднее время загрузки json-а на несколько различных размеров и поставил таймер 33/66/99/~100 :)


  1. csharpreader
    11.07.2023 17:35
    +7

    Где-то именно на Хабре в комментах было: мол, в одной конторе прикрутили красивую фичу – отправляешь заявку во внутреннюю техподдержку и любуешься на прогресс-бар по срочным заявкам. В какой-то момент выяснилось, что прогресс-бар – просто картинка. Ребятам в техподдержку падала срочная заявка, и пока они её руками делали, пользователю отрисовывался красивый прогресс выполнения ))


    1. velon Автор
      11.07.2023 17:35

      Дёшево и сердито, ведь достаточно проверять текущий статус заявки и знать время которое на срочные заявки выделяется. Зато вау-эффект какой...


      1. Ivan22
        11.07.2023 17:35

        "Солдат спит - прогресс бар идет" (с)


  1. ReinRaus
    11.07.2023 17:35
    +22

    Иногда полоса загрузки или хотя бы спиннер очень нужны в приложении. Пусть даже на несколько секунд.

    В приложении "Huawei Health" есть кнопка "Проверить обновление прошивки носимого устройства". Ты её тыкаешь и через доли секунды появляется результат, что уже установлена самая свежая версия ПО. Даже не верится, что там что-то проверялось. Вот если бы покрутился спиннер пару секунд, то такой результат был бы более уважительным :)

    P.S. Это не шутка. Часто тыкаю кнопку "Проверить обновления" дважды из-за слишком быстрого ответа :)


    1. AVX
      11.07.2023 17:35
      +5

      Где-то писали похожее про кнопку "сохранить" в офисе или libreoffice, не помню. Типа, многие нажимают несколько раз, потому что слишком быстро сохраняется и не понятно, то ли сработало, то ли нет. Хотя вроде как сейчас обозначают и цветом значка кнопки и сообщением где-то в строке статуса, звездочкой в названии или ещë как-то.


      1. Wesha
        11.07.2023 17:35
        +6

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

        А у нормальных людей после сохранения текст на кнопке меняется на "СОХРАНЕНО!" и она становится неактивной.


        1. AVX
          11.07.2023 17:35
          +6

          В libreoffice так и есть. Если изменения документа были, то становится доступной.

          P. S. Во времена дискет ещë и звуковые эффекты - жужжит, трещит, и точно понятно, что оно там сохранялось. (но копию файла сделать надо!)


      1. SquareRootOfZero
        11.07.2023 17:35
        +15

        Дык, в той же Винде, бывает, сделаешь двойной клик по ярлыку на рабочем столе — и чо-то никакой реакции не видно, и сиди, гадай: а оно запускается или чо? а может, я не докликнул? а может, оно упало уже? Подождёшь, ещё раз даблкликнешь, потом ещё. Через несколько секунд оно возникает на экране в пяти экземплярах. В каком-то линуксовом оконном мессенджере, помню, было интуитивнее: кликнул, иконка начала как-то жмыхаться туда-сюда — значит, ты, во всяком случае, всё правильно нажал.


        1. AVX
          11.07.2023 17:35

          В KDE точно отклик курсора есть, и понятно, если сработало. И это настраивается.


        1. boingo-00
          11.07.2023 17:35

          В плазме у курсора прыгает значок приложения
          В MATE на панели задач пишется "запускается AppName"


  1. Viacheslav01
    11.07.2023 17:35
    +3

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


    1. madcatdev
      11.07.2023 17:35
      +2

      Самый тут простой способ - это крутящееся колесико, и ничего с заполнением мудрить не надо.


      1. ris58h
        11.07.2023 17:35
        +8

        С колёсиком работу не отличить от зависания, а вот прогрессбар, который заполняется (пусть и фальшиво) сразу успокаивает.


        1. madcatdev
          11.07.2023 17:35
          +2

          Колесико не крутится - значит все зависло.


          1. Shavadrius
            11.07.2023 17:35
            +5

            Если колесико реализовано через показ gif, то оно и будет крутится, только бесконечно)


          1. Gummilion
            11.07.2023 17:35
            +4

            Обычно за отрисовку колесика отвечает система, и даже если UI тред завис - оно будет продолжать крутиться. Чтобы было "по-честному" - надо, чтобы именно из рабочего потока периодически вызывалась функция поворота колесика на несколько градусов, но кто с таким будет заморачиваться?


        1. mayorovp
          11.07.2023 17:35

          Успокаивает он только до тех пор пока программа не зависнет с этим прогресс-баром.


      1. Viacheslav01
        11.07.2023 17:35
        +7

        Колесико не дает ощущения работы и какого то прогресса в ее выполнении, а прогресс бар дает.


    1. AVX
      11.07.2023 17:35
      +5

      Давным-давно, лет 19 назад, писал на vb6 программу для диплома, по обработке данных (численное вычисление магнитных полей было вроде). Так комп не особо шустрый, и вычисления занимали много часов. Пришлось почти сразу придумывать прогрессбар или два даже, иначе не видно было, движется там или повисло всë по какой-то причине. И вроде ничего, норм было. Пока не узнал что можно приоритет процесса через winapi менять, ну и поставил в высокий очень - а при нëм вычисления довольно быстрее стали, но прогрессбар уже не отрисовывал - его приоритет был ниже, и казалось, что зависает. Потом сделал крутилку для оперативного переключения приоритета прямо во время вычислений - можно было выбрать что важнее - несколько быстрее вычислить, или чаще видеть изменения прогресса. Без него проблемно прям.

      А вот в mathcad'е не было прогрессбара, и когда забиваешь огромную формулу чтобы он что-то там упростил или решил уравнение в символьном виде - всë зависало, и непонятно было, сколько ждать. На некоторых задачах у меня комп жужжал часов 6. Кто-то из однокурсников говорил, что было и сутки ожидания, пока посчитает, но того стоило. Вручную все эти фурье и z-transform считать и дифференцирование-интегрирование - ну его нафиг. Вот что мешало там тоже встроить прогрессбар?


      1. mayorovp
        11.07.2023 17:35

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


        А прогрессбару (точнее, потоку UI) тоже можно приоритет менять, странно что вы этого не нашли...


        1. AVX
          11.07.2023 17:35
          +2

          Так я не программист :) Там и код не очень-то был, я подозреваю. В то время интернета-то нормального не было, диалап по карточкам, и как бы не соврать, всё ещё WinME стояла на на компе. Про закрытие программ я экспериментировал, вплоть до замены shell :-) Но на одном ядре AMD Duron 800 далеко не уедешь, как ни крути.


          1. Wesha
            11.07.2023 17:35

            Так я не программист

            Маску клавиатуру на стройке в стартапе нашёл?


      1. ElvenSailor
        11.07.2023 17:35

        одно из двух:

        1 реально некогда переключить контекст (т.е шевеление прогрессбаром замедлит обсчёт задачи) - вполне реально на железе тех времён

        2 Объём задачи точно не известен, в процессе выполнения могут образоваться новые штуки, которые надо считать - т.е. хрен знает что взять за 100%. Если сделать в лоб, прогресс будет отползать назад, а люди такого не любят =)


  1. diakin
    11.07.2023 17:35

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


  1. DreamingKitten
    11.07.2023 17:35
    +16

    Ааааа, так вот кто пишет эти прогрессбары, которые останавливаются на 99% и висят там дольше, чем до этих 99% прогресс шёл...


  1. masai
    11.07.2023 17:35
    +1

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


  1. Divisi0n
    11.07.2023 17:35
    +8

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


    1. ganzmavag
      11.07.2023 17:35
      +3

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


      1. Divisi0n
        11.07.2023 17:35
        +9

        Старый добрый Total Commander наличие разных/мелких файлов не смущает. А ещё эта "подготовка к копированию", которая длится дольше, чем само копирование. Вы там файлам шапочки надеваете перед походом в другую папку?


        1. ganzmavag
          11.07.2023 17:35
          +4

          Вот вспомнил Total Commander, но показалось, что там тоже были проблемы какие-то с точностью. Надо ради интереса что-нибудь мелкое в больших количествах покопировать.
          Подготовка к копированию - загадочная штука, давно интересно, что они реально там готовят. Не удивлюсь, если все это время пытаются собрать данные для прогресс-бара.


          1. develmax
            11.07.2023 17:35
            +7

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


            1. SuhoffGV
              11.07.2023 17:35
              +1

              Если файл только для чтения Total об это скажет только в процессе переноса когда дойдет до файла. На этапе подсчета не скажет.

              Что сильно бесит. Поставил копироваться 100500 файлов и ушел, а он на 10м файлике встал и ждет от тебя ответа.


              1. Divisi0n
                11.07.2023 17:35
                +4

                это можно предусмотреть


          1. censor2005
            11.07.2023 17:35

            Насколько помню, в настройках Total Commander была галочка, которая позволяла не подсчитывать время копирования, тем самым копирование ускорялось, но при этом прогресс-бар не показывал точную статистику.


    1. SquareRootOfZero
      11.07.2023 17:35
      +3

      Это юзер порядка ста лет уже подождал и ещё примерно столько же осталось?


      1. Gummilion
        11.07.2023 17:35
        +9

        Пф, всего-то сто лет... Мне как-то предложили подождать где-то под 300 миллиардов лет!


        1. SuperTEHb
          11.07.2023 17:35
          +13

          ... и ещё полчаса.


          1. Mingun
            11.07.2023 17:35
            +1

            Забота о пользователе, сообщают ему точное время ожидания!


          1. AVX
            11.07.2023 17:35
            +2

            да они издеваются что ли?! какие ещё сверху полчаса

            :)


    1. Krouler7
      11.07.2023 17:35
      +5

      Зато при поиске в проводнике Windows есть та самая - фейковая загрузка, которая расположена на адресе директории. Постепенно замедляясь бежит к краю, но никогда не доходит.


      1. Armitage1986
        11.07.2023 17:35

        Десятая винда, прогресс-бар доходит до конца (после чего исчезает, оставляя обычную строку "Результаты поиска в ...").


      1. roginvs
        11.07.2023 17:35
        +1

        В npm есть пакет для фронтэнда который делает тоже самое, почти миллион загрузок в неделю https://www.npmjs.com/package/nprogress

        Ну что делать если пользователям так больше нравится


        1. velon Автор
          11.07.2023 17:35
          +1

          Тут наверно уместнее не "нравится", а "привыкли".

          Или второй вариант, я и за собой иногда такое замечают, когда оправдываю какие-то недоделки тем что и у "ООО "Майкрософт" (или подставьте любое название) так же. Ведь зачем заморачиваться, если даже ОНИ не заморочились, - значит норм.


  1. moonster
    11.07.2023 17:35
    +4

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

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

    Откуда брать процент? Насочиняли всякой сложной логики, как учитывать распараллеливаемые операции, как вложенные, что делать, если текущая операция добавит другую (дада, прогресс откатывался) и еще всякие интересные кейсы.

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

    В один прекрасный момент я просто выбросил всю сложную логику.

    Вместо нее начал считать так: от момента начала операции в течении ожидаемого максимального времени операции (эмпирическое значение, десятки секунд) процент равномерно бежит от 0 до 60, далее - каждые 10 секунд добавляется по проценту, и так до 99.

    С тех пор прошел год. Никто не жаловался.


  1. ivankudryavtsev
    11.07.2023 17:35
    +2

    Эх, сервелат, ностальджи


  1. JPEGEC
    11.07.2023 17:35

    Таким образом мы дурим пользователя за его же деньги. И обмануть его не
    трудно! Он сам обманываться рад! И это не фигура речи, дословно не
    помню, но желание коллективного пользователя было сформулировано как-то
    так: “Сделайте хоть что-нибудь чтобы мы видели что приложение не
    зависло, и примерно представляли сколько ещё осталось ждать”.

    Простите, а вывести таймер чем плохо? И видно что процесс не завис и обмана нет.


    1. velon Автор
      11.07.2023 17:35
      +4

      Просто таймер который показывает сколько времени прошло?

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


  1. TheScriptCompany
    11.07.2023 17:35
    +4

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


    1. velon Автор
      11.07.2023 17:35
      +6

      Я и сам как пользователь этому удивляюсь. Но...

      Тут всё гораздо хуже чем кажется:

      • загрузка идёт плавно - пользователи удивляются

      • загрузка идёт рывками - пользователи удивляются

      • загрузка не идёт но приложение думает - пользователи удивляются

      • приложение запустилось без загрузки - пользователи удивляются

      Пользователи всегда удивляются. Можно потратить много времени на честную оценку но пользователи всё равно будут удивляться.


      1. AUser0
        11.07.2023 17:35
        +1

        Ещё и хуже чем кажется?! Удивительно!


    1. allcreater
      11.07.2023 17:35
      +2

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

      Но, в отличие от поддельного, тут есть два преимущества: время подвисания более-менее фиксированное и зависит обычно только от производительности девайса, а еще это можно зарефакторить и таки сделать по-человечески =)


  1. ieroglyph
    11.07.2023 17:35
    +22

    Разрабатывали мы один проект АРМ на базе Линукс. По сути, запускалось наше ПО автоматически при старте системы в полноэкранном режиме, но начальные экраны загрузки системы были видны, что раздражало заказчика и коробило общее чувство прекрасного. Пришли к тому, что в качестве изображения silent boot поставили "лого" проекта, на экране загрузки самой системы - то же лого с названием проекта и статическое изображение прогрессбара на 4%. Затем на рабочем столе стояло то же изображение с прогрессбаром на 11%. Потом уже, когда стартовало наше приложение, начинали с того же изображения, готовности 15% и потихоньку доводили до 100% под контролем сложной логики с получением ответов о готовности разных железяк вперемежку с несколькими sleep()ами.


    1. Vitaly48
      11.07.2023 17:35
      +1

      Эта картинка подходит тут как никогда


    1. AVX
      11.07.2023 17:35
      +3

      Мне вот как раз больше нравится, когда приложение (или ОС) честно показывает текстом, что сейчас делается, и не надо особо прогресса никакого, ну можно счётчик типа "1 из 20: запуск службы хххх", если применимо и заранее известно количество. Можно ведь и в программах так делать (и во многих делают), что если программа что-то загружает, пишет, какой файл загружается, если что-то вычисляет - что именно вычисляет (если это может быть долго). А всякие splash-screen'ы только в неведении держат. Может оно и оправдано, если нужно скрыть от пользователя внутреннее устройство (неважно что мы там делаем, вот тебе готовый результат, а пока смотри картинку).


  1. gruzoveek
    11.07.2023 17:35
    +4

    Делали внутренний продукт и там был один тяжелый запрос в БД. Ответ ехал около 40 сек после всех оптимизаций. Чтоб юзеры не думали что все подвисло, я прикрутил фейковый прогресс-бар (спиннеров тогда еще не придумали), он мелкими рандомными рывками шел к 100% в течение тех 40 секунд. Потом поменяли это дело на спиннер, медитировать на который юзерам нравилось больше. Процент "загрузки" отрисовывали внутри спиннера по тому же алгоритму, по которому двигался прогресс-бар.


  1. wnder
    11.07.2023 17:35
    +3

    Год эдак 2004, мы пишем на Дельфи 7. На нашем заводе активно внедряют юникса и делают локалку.
    Мы пишем программу, которая - о чудо, локалка же! - ходит не только в промышленную сеть, но и в локалку. Установщик все подтягивает, подкачивает, настраивается, опрашивает профибас, гребет данные с серверов в соседнем здании по эзернет.

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

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

    Устанавливаем программу на рабочем месте начальника смены - и дядька задумчиво смотрит как прогрессбар добежал до 100% и побежал к нулю. И примерно при 50% все закончилось.

    Хммм... - сказал дядька

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


    1. velon Автор
      11.07.2023 17:35
      +10

      Если бы я увидел как прогресс бар побежал обратно, я бы испугался: "эй куда, всё же было, вернись я всё прощу"


      1. wnder
        11.07.2023 17:35
        +2

        Мы импровизировали, а заказчик задачи "завис" на стадии приемки. Но принял :)


        1. SuperTEHb
          11.07.2023 17:35
          +21

          Это вам казалось, что завис. На нём прогрессбара просто не было.


          1. velon Автор
            11.07.2023 17:35
            +10

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

            И просто на работе сидишь - крутишь спинер, значит работаешь, а не зависаешь


      1. Gummilion
        11.07.2023 17:35
        +9

        Тем более, в каком-то из стандартных установщиков (то ли InstallShield, то ли MSI) если при установке происходил сбой, прогресс реально откатывался на 0. Так что повод волноваться действительно был.


      1. sergej_pipets
        11.07.2023 17:35

        "Удаление временных файлов и прочего мусора"


      1. 9982th
        11.07.2023 17:35
        +1

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


        1. mayorovp
          11.07.2023 17:35

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


  1. mrkerzak
    11.07.2023 17:35
    +2

    Мы когда в колледже делали курсовые и дипломы для понтов вставляли меню загрузки, типо смотри как могу


    1. velon Автор
      11.07.2023 17:35
      +2

      Это же хорошо. когда у студиков есть мотивация что-то делать, пусть даже эта мотивация: понты перед однокурсниками. Тоже двигатель развития


  1. Grigorenkovic
    11.07.2023 17:35
    +2

    Тоже была задача сделать прогресс-бар при получении данных из БД. Сделал таблицу для хранения замеров производительности в зависимости от параметров и отборов, и подставлял нужное количество секунд.


  1. allcreater
    11.07.2023 17:35
    +1

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


  1. koreychenko
    11.07.2023 17:35
    +1

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


  1. infino1
    11.07.2023 17:35
    +4

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

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


  1. ZvoogHub
    11.07.2023 17:35
    -3

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

    Если серьёзно - какой-то блоггер почему-то решил что полоса обязательно должна означать время и двигаться равномерно.

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

    Пользователи к этому привыкли и вполне лояльно относятся.

    Не надо искать проблему там где её нет.


    1. konst90
      11.07.2023 17:35
      +3

      Мне как пользователь важно знать, сколько будет выполняться задача, хотя бы примерно. Перекур? Обед? На ночь запустить?


  1. balamutang
    11.07.2023 17:35
    +4

    Мы так для одной конторы контроллер делали для сбора данных с картридеров по Wiegand, стартовал то он моментально, но чтобы прибор казался солиднее - я добавил визуальный процесс инициализации: по дисплею 16х2 две секунды полз прогрессбар. Все были в восторге.


  1. shasoftX
    11.07.2023 17:35
    +3

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

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


    1. velon Автор
      11.07.2023 17:35

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

      Вот она - фабрика грёз, со всеми последствиями


  1. Sild
    11.07.2023 17:35

    А размеры модулей сильно менялись? Почему бы было не захардкодить размер в коде, если в заголовках пусто? Это было бы куда менее трудозатрадно


    1. velon Автор
      11.07.2023 17:35
      +1

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

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

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


  1. gluck59
    11.07.2023 17:35
    +5

    Как-то раз меня с честным прогрессбаром достал главный продажник: мол чо это у тебя полоска доходит только до 90 и на этом месте все нужное уже появляется на экране? Не объяснишь ведь продажнику, что последний файл залетает быстрее его ожиданий... Пришлось добавить "процентов" прогрессбару, чтобы он успевал доползти до 100 и продажник ушел довольный.

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

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


  1. GnuriaN
    11.07.2023 17:35

    Это было давно.... Был Qbasic, который поставлялся отдельно с редактором и компилятором на "Англицком" языке :-). Тестовый интерфейс программы с поддержкой мыши. "Аля драйвер" был написан на псевдокодах и грузился в память. В зависимости от мощности ПК 286, 386, 486.. Было найдено оптимальное время которое требовалось на загрузку всего (что бы мышка заработала) и был сделан экран загрузки в котором через цикл была загрузка экрана.... Это был 2000 год.... 11 класс....


  1. Sensimilla
    11.07.2023 17:35
    +1

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


  1. gres_84
    11.07.2023 17:35
    +1

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