<p> Несмотря на стремительное <a href="http://www.podlipensky.com/post/2008/10/internet-next-version.aspx" target="_blank" title="развитие интернета">развитие интернета</a>, проблема оптимизации веб-приложений стоит также остро, как и во времена dialup-подключений по советской вермишели. </p> <p> В сентябре 2006 года Питер Севчик (Peter Sevcik) и Ребекка Ветцель (Rebecca Wetzel) из компании NetForecast опубликовали документ, именуемый "Field Guide to Application Delivery Systems" («Полевое руководство по системам доставки приложений»). Основное внимание в документе было уделено улучшению производительности приложений в глобальных сетях (wide area network – WAN), и в нем было приведено уравнение </p> <p> <a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/yrav_2.gif"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/yrav_thumb.gif" border="0" alt="yrav" title="yrav" width="244" height="42" /></a> , где </p> <ul> <li><strong>R</strong> - время ответа. Общее время с запроса страницы пользователем (обычно переходом по ссылке и т.п.) до полной визуализации страницы на его компьютере. Обычно измеряется в секундах. </li> <li><strong>Полезная нагрузка -</strong> общее число байтов, отправленных обозревателю, включая разметку и все ресурсы (такие как файлы CSS, JS и изображений). </li> <li><strong>Пропускная способность - </strong>скорость передачи данных обозревателю и от него. Может быть асимметрична и представлять несколько скоростей, если данная страница создается из нескольких источников. Обычно усредняется для создания единого выражения пропускной способности в байтах в секунду. </li> <li><strong>AppTurns - </strong>число файлов ресурсов, требуемых страницей. Они включают файлы CSS, JS, изображений и любые другие файлы, извлекаемые обозревателем в процессе визуализации страницы. Уравнение учитывает страницу HTML отдельно, добавляя время приема-передачи (round-trip time – RTT) перед выражением AppTurns. </li> <li><strong>RTT - </strong>время, необходимое для приема и передачи данных, вне зависимости от числа переданных байтов. Каждый запрос тратит минимум одно RTT для самой страницы. Обычно измеряется в миллисекундах. </li> <li><strong>Cs </strong>- время вычислений на сервере. Время, уходящее у кода на запуск, извлечение данных из базы данных и составление ответа, отправляемого обозревателю. Измеряется в миллисекундах. </li> <li><strong>Cc - </strong>время вычислений на клиенте. Время, уходящее у обозревателя на визуализацию HTML на экране, исполнение JavaScript, применение правил CSS, итд. </li> </ul> <p> Этот пост будет началом серии статей по оптимизации производительности вашего веб-приложения. </p> <p> Рассмотрим первый параметр, влияющий на время загрузки страницы – <strong>полезная нагрузка</strong> или объем полезных данных. </p> <p> <strong>Архивирование(сжатие) контента страницы</strong> </p> <p> Первое, что мы можем сделать - это сжать наш html, css и js код с помощью GZip или Deflate(~40% лучше, чем gzip) сжатия. Не все браузеры принимают сжатый контент, поэтому необходимо проверять, содержит ли запрос заголовок Accept-Encoding со значением “gzip” или “deflate”: </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 100.02%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 171px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">bool</span> CanGZip(HttpRequest request) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 2:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 3:</span> <span style="color: #0000ff">string</span> acceptEncoding = request.Headers[<span style="color: #006080">"Accept-Encoding"</span>]; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 4:</span> <span style="color: #0000ff">if</span> (!<span style="color: #0000ff">string</span>.IsNullOrEmpty(acceptEncoding) && </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 5:</span> (acceptEncoding.Contains(<span style="color: #006080">"gzip"</span>) || acceptEncoding.Contains(<span style="color: #006080">"deflate"</span>))) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 6:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 7:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 8:</span> } </pre> </div> </div> <p> Программно сжать контент позволяет пространство имен System.IO.Compression </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 100.04%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 210px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">byte</span>[] Compressor(<span style="color: #0000ff">byte</span>[] buffer, <span style="color: #0000ff">string</span> encodingType) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 2:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 3:</span> <span style="color: #0000ff">using</span> (MemoryStream memStream = <span style="color: #0000ff">new</span> MemoryStream()) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 4:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 5:</span> Stream compress = <span style="color: #0000ff">null</span>; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 6:</span>  </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 7:</span> <span style="color: #008000">// Choose the compression type and make the compression </span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 8:</span> <span style="color: #0000ff">if</span> (String.Equals(encodingType, <span style="color: #006080">"gzip"</span>, StringComparison.Ordinal)) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 9:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 10:</span> compress = <span style="color: #0000ff">new</span> GZipStream(memStream, CompressionMode.Compress); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 11:</span> } </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 12:</span> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (String.Equals(encodingType, <span style="color: #006080">"deflate"</span>, StringComparison.Ordinal)) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 13:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 14:</span> compress = <span style="color: #0000ff">new</span> DeflateStream(memStream, CompressionMode.Compress); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 15:</span> } </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 16:</span> <span style="color: #0000ff">else</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 17:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 18:</span> <span style="color: #008000">// No compression </span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 19:</span> <span style="color: #0000ff">return</span> buffer; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 20:</span> } </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 21:</span>  </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 22:</span> compress.Write(buffer, 0, buffer.Length); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 23:</span> compress.Dispose(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 24:</span>  </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 25:</span> <span style="color: #0000ff">return</span> memStream.ToArray(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 26:</span> } </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 27:</span> } </pre> </div> </div> <p> После чего вам остается лишь добавить сжатый поток в ответ пользователю: </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 99.75%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 59px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> HttpContext.Response.OutputStream.Write(compressedData, 0, compressedData.Length); </pre> </div> </div> <p> Если же у вас есть доступ к IIS консоли, то вы можете настроить сжатие на уровне IIS(версии 7): </p> <p> <a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/iis_compression1_2.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/iis_compression1_thumb.jpg" border="0" alt="iis_compression1" title="iis_compression1" width="244" height="182" /></a>  </p> <p> <a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/iis_compr2_2.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/iis_compr2_thumb.jpg" border="0" alt="iis_compr2" title="iis_compr2" width="244" height="88" /></a> </p> <p> <strong>Очистка JS и CSS кода</strong> </p> <p> Также мы можем очистить наш css и js код от лишних символов. </p> <p> Например, следующий css код </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 99.27%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 173px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff">body</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 2:</span> <span style="color: #0000ff">font-size</span>:<span style="color: #006080">14px;</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 3:</span> <span style="color: #0000ff">font-family</span>:<span style="color: #006080">Arial;</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 4:</span> } </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 5:</span> <span style="color: #0000ff">h1</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 6:</span> <span style="color: #0000ff">font-size</span>:<span style="color: #006080">14px;</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 7:</span> <span style="color: #0000ff">font-family</span>:<span style="color: #006080">Arial;</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 8:</span> } </pre> </div> </div> <p> можно преобразовать в следующую строку </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 98.47%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 61px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff">body</span>,<span style="color: #0000ff">h1</span>{<span style="color: #0000ff">font</span>:14px arial} </pre> </div> </div> <pre>   </pre> <p> Основной принцип подобных алгоритмов – это превращение человеко-читемого кода в сжатый код понятный лишь компилятору. </p> <p> Для javascript кода наибольшей популярностью пользуются два инструмента <a href="http://www.crockford.com/javascript/jsmin.html">JSMin</a> (автор: Douglas Crockford) и <a href="http://dean.edwards.name/packer/">Packer</a> (автор: Dean Edward). Алгоритмы упаковки обоих инструментов обрабатывают(obfuscate) любой js код, но только при условии, что вы корректно завершаете все javascript-выражения символом “;” (включая объявление функций). </p> <p> Для css кода вы можете воспользоваться утилитой под названием <a href="http://www.google.com/url?sa=t&source=web&ct=res&cd=1&url=http%3A%2F%2Fcsstidy.sourceforge.net%2F&ei=zf7sSLb6Fo--0gXCqNnZDA&usg=AFQjCNGSBrPKKRuUhHzzfO2BCQtuFU4idw&sig2=DKv2LIIveRuWMpqiyE4jgA" target="_blank">CSSTidy</a> или одним из множества подобных <a href="http://www.cssoptimiser.com/" target="_blank">онлайн-сервисов</a>. </p> <p> <strong>Оптимизация графики</strong> </p> <p> Допустим в вашей базе данных, на жестком диске или любом другом хранилище расположена ваша любимая фотография размером 200x400 пикселей (24 Kb). Но вам необходимо отобразить ее на странице в виде изображения размером 100х200 пикселей. В таком случае, подобный код </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.74%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 68px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">img</span> <span style="color: #ff0000">src</span><span style="color: #0000ff">="/images/mybestphoto.png"</span> <span style="color: #ff0000">width</span><span style="color: #0000ff">="100"</span> <span style="color: #ff0000">height</span><span style="color: #0000ff">="200"</span> <span style="color: #ff0000">alt</span><span style="color: #0000ff">="My Best Photo"</span> <span style="color: #0000ff">/></span> </pre> </div> </div> <br /> решит вашу проблему, но при этом размер вашей фотографии останется прежним - 24 Kb. Хотя, если бы вы сжали(изменили размер) ее в фотопопе, то "вес" файла существенно бы уменьшился. <p> Для того, чтобы достичь подобного эффекта, вам необходимо программно, на сервере сжать вашу графику. Примерно таким образом: </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> SaveResizedImage(<span style="color: #0000ff">string</span> imagePath, <span style="color: #0000ff">int</span> width, <span style="color: #0000ff">int</span> height) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 2:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 3:</span> <span style="color: #0000ff">int</span> newResizeimageId; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 4:</span> <span style="color: #008000">// Читаем графический файл с жесткого диска</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 5:</span> FileStream fs = File.OpenRead(imagePath); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 6:</span> <span style="color: #0000ff">byte</span>[] data = <span style="color: #0000ff">new</span> <span style="color: #0000ff">byte</span>[fs.Length]; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 7:</span> fs.Read(data, 0, data.Length); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 8:</span> MemoryStream ms = <span style="color: #0000ff">new</span> MemoryStream(data); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 9:</span> Bitmap bmp = <span style="color: #0000ff">new</span> Bitmap(ms); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 10:</span> System.Drawing.Image imgPhoto = (Image)bmp; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 11:</span> <span style="color: #008000">// Настраиваем Encoder, для преобразования графики</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 12:</span> Encoder qualityEncoder = Encoder.Quality; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 13:</span> EncoderParameters parameterList = <span style="color: #0000ff">new</span> EncoderParameters(1); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 14:</span> EncoderParameter qualityParameter = <span style="color: #0000ff">new</span> EncoderParameter(qualityEncoder, 50L); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 15:</span> parameterList.Param[0] = qualityParameter; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 16:</span> <span style="color: #008000">// По расширению файла определяем кодек</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 17:</span> ImageCodecInfo codec = GetCodecFromExtension(Path.GetExtension(imagePath)); <span style="color: #008000">//GetCodecFromExtension в этом листинге не приведена.</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 18:</span> <span style="color: #008000">// Создаем пустую канву. Измененная графика будет записана в эту канву.</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 19:</span> Bitmap bmPhoto = <span style="color: #0000ff">new</span> Bitmap(width, height); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 20:</span> bmPhoto.SetResolution(10, 10); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 21:</span> Graphics grPhoto = Graphics.FromImage(bmPhoto); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 22:</span> grPhoto.SmoothingMode = SmoothingMode.HighSpeed; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 23:</span> grPhoto.InterpolationMode = InterpolationMode.High; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 24:</span> grPhoto.PixelOffsetMode = PixelOffsetMode.HighSpeed; </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 25:</span> grPhoto.DrawImage(imgPhoto, <span style="color: #0000ff">new</span> Rectangle(0, 0, width, height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 26:</span> <span style="color: #008000">// Сохраняем файл в память, а затем убеждаемся, что все ресурсы освобождены корректно.</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 27:</span> MemoryStream mm = <span style="color: #0000ff">new</span> MemoryStream(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 28:</span> bmPhoto.Save(mm, codec, parameterList); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 29:</span> imgPhoto.Dispose(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 30:</span> bmPhoto.Dispose(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 31:</span> grPhoto.Dispose(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 32:</span> <span style="color: #008000">//Сохраняем массив байт измененной графики куда необходимо. </span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 33:</span> newResizeimageId = SaveImageToDb2(mm.GetBuffer()); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 34:</span> mm.Dispose(); </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 35:</span> } </pre> </div> </div> <p> Хочу обратить ваше внимание на строчку </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 58px; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> bmPhoto.SetResolution(10, 10); </pre> </div> </div> <p> Где мы можем изменить качество нашей графики, установив новое разрешение. Результаты могут быть примерно такими </p> <table border="0" cellspacing="0" cellpadding="2" width="400"> <tbody> <tr> <td width="80" valign="top"><a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_thumb.jpg" border="0" alt="avatar" title="avatar" width="96" height="96" /></a></td> <td width="80" valign="top"><a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_0_2.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_0_thumb.jpg" border="0" alt="avatar_0" title="avatar_0" width="96" height="96" /></a><a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_2_2.jpg"></a></td> <td width="80" valign="top"><a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_2_2.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_2_thumb.jpg" border="0" alt="avatar_2" title="avatar_2" width="96" height="96" /></a></td> <td width="80" valign="top"><a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_5_2.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_5_thumb.jpg" border="0" alt="avatar_5" title="avatar_5" width="96" height="96" /></a></td> <td width="80" valign="top"><a href="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_8_2.jpg"><img style="border-width: 0px" src="http://www.podlipensky.com/image.axd?picture=WindowsLiveWriter/061a5f8f963f_84A0/avatar_8_thumb.jpg" border="0" alt="avatar_8" title="avatar_8" width="96" height="96" /></a></td> </tr> <tr> <td width="80" valign="top">2.58 kB</td> <td width="80" valign="top">2.86 kB <font color="#ff0000">(+10%)</font></td> <td width="80" valign="top">1.98 kB <br /> <font color="#008000">(-23%)</font></td> <td width="80" valign="top">1.55 kB <br /> <font color="#008000">(-39%)</font></td> <td width="80" valign="top">672 bytes <br /> <font color="#008000">(-74%)</font></td> </tr> </tbody> </table> <p> Обратите внимание на то, что после небольшого ухудшения качества, размер изображения наоборот - возрос. Дальнейшее же уменьшения разрешения привело к уменьшению размера файла. Также учтите, что, чем больше первоначальный размер изображения, тем эффективней будет сжатие без визуальных потерь качества. Ухудшать качество небольших картинок, как видите, смысла нет. </p> <p> <strong>Отключаем ViewState</strong> </p> <p> Возможно вы подумали, о нехитром свойстве страницы EnableViewState="false". Отключение ViewState с помощью вышеупомянутого свойства действительно уменьшит размер скрытого поля, но не избавит вас от него. В отдельных случаях полезно и вовсе избавиться от ViewState. Сделать это можно, переопределив метод SavePageStateToPersistenceMedium, и “забыв” вызвать в нем базовый метод. </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> SavePageStateToPersistenceMedium(<span style="color: #0000ff">object</span> state) </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 2:</span> { </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 3:</span> <span style="color: #008000">//base.SavePageStateToPersistenceMedium(state); </span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <span style="color: #606060"> 4:</span> } </pre> </div> </div> <p> <strong>Избавляемся от длинных ID, сгенерированных ASP.NET</strong> </p> <p> К сожалению, не существует способа избавиться от длинных ID в debug-версии вашего веб-сайта. Но когда ваш проект уже готов и скомпилирован, то вы можете обработать сборки, обфускатором. При этом, следует указать обфускатору заменять все имена контролов на более короткие. Таким образом вместо <em>ctl00_body_WidgetPanelsLayout_WidgetContainer65_WidgetBodyPanel</em>, ваша панель будет иметь id равное, например <em>А. </em>Будьте осторожны с подобной оптимизацией – ваш javascript код может не работать, если функционал привязан к заранее заданным ID. Хотя, если вы использовали что-то похожее на следующий код </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> $get(<span style="color: #006080">'<%= TextBox1.ClientID %>'</span>) </pre> </div> </div> <p> то обфускатор не нарушит вашего функционала. </p> <p> <strong>Полезные ссылки</strong> </p> <p> <a href="http://blog.madskristensen.dk/post/Reduce-the-weight-of-stylesheets-by-3525-at-runtime.aspx">Reduce the weight of stylesheets by 35% at runtime</a> </p> <p> <a href="http://blog.madskristensen.dk/post/HTTP-compression-in-ASPNET-20.aspx">HTTP compression in ASP.NET 2.0</a> </p> <p> <a href="http://blog.madskristensen.dk/post/Compression-and-performance-GZip-vs-Deflate.aspx">Compression and performance - GZip vs. Deflate</a> </p> <p> <a href="http://www.mironabramson.com/blog/post/2007/09/Compress-your-pages2c-css2c-js-and-WebResourcesaxd-files-for-better-performance.aspx">Compress your pages, css, js and WebResources.axd files for better performance</a> </p> <p> <a href="http://www.askapache.com/tools/online-compression-tool-compares-packer-jsmin-dojo-and-yui-compressor.html">Online Tool compares Packer, JSMin, Dojo, and YUI Compressor</a> </p> <p> <a href="http://www.dailyblogtips.com/speed-up-your-site-optimize-your-css/" target="_blank">Speed Up Your Site: Optimize your CSS</a> </p> <p> <a href="http://www.bloggingpro.com/archives/2006/08/17/css-optimization/">CSS Optimization: Make Your Sites Load Faster for Free</a> </p>

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

В сентябре 2006 года Питер Севчик (Peter Sevcik) и Ребекка Ветцель (Rebecca Wetzel) из компании NetForecast опубликовали документ, именуемый "Field Guide to Application Delivery Systems" («Полевое руководство по системам доставки приложений»). Основное внимание в документе было уделено улучшению производительности приложений в глобальных сетях (wide area network – WAN), и в нем было приведено уравнение

yrav , где

  • R - время ответа. Общее время с запроса страницы пользователем (обычно переходом по ссылке и т.п.) до полной визуализации страницы на его компьютере. Обычно измеряется в секундах.
  • Полезная нагрузка - общее число байтов, отправленных обозревателю, включая разметку и все ресурсы (такие как файлы CSS, JS и изображений).
  • Пропускная способность - скорость передачи данных обозревателю и от него. Может быть асимметрична и представлять несколько скоростей, если данная страница создается из нескольких источников. Обычно усредняется для создания единого выражения пропускной способности в байтах в секунду.
  • AppTurns - число файлов ресурсов, требуемых страницей. Они включают файлы CSS, JS, изображений и любые другие файлы, извлекаемые обозревателем в процессе визуализации страницы. Уравнение учитывает страницу HTML отдельно, добавляя время приема-передачи (round-trip time – RTT) перед выражением AppTurns.
  • RTT - время, необходимое для приема и передачи данных, вне зависимости от числа переданных байтов. Каждый запрос тратит минимум одно RTT для самой страницы. Обычно измеряется в миллисекундах.
  • Cs - время вычислений на сервере. Время, уходящее у кода на запуск, извлечение данных из базы данных и составление ответа, отправляемого обозревателю. Измеряется в миллисекундах.
  • Cc - время вычислений на клиенте. Время, уходящее у обозревателя на визуализацию HTML на экране, исполнение JavaScript, применение правил CSS, итд.

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

Рассмотрим первый параметр, влияющий на время загрузки страницы – полезная нагрузка или объем полезных данных.

Архивирование(сжатие) контента страницы

Первое, что мы можем сделать - это сжать наш html, css и js код с помощью GZip или Deflate(~40% лучше, чем gzip) сжатия. Не все браузеры принимают сжатый контент, поэтому необходимо проверять, содержит ли запрос заголовок Accept-Encoding со значением “gzip” или “deflate”:

   1: private bool CanGZip(HttpRequest request) 
   2: { 
   3:         string acceptEncoding = request.Headers["Accept-Encoding"]; 
   4:         if (!string.IsNullOrEmpty(acceptEncoding) && 
   5:              (acceptEncoding.Contains("gzip") || acceptEncoding.Contains("deflate"))) 
   6:             return true; 
   7:         return false; 
   8: }

Программно сжать контент позволяет пространство имен System.IO.Compression

   1: public static byte[] Compressor(byte[] buffer, string encodingType) 
   2:      { 
   3:          using (MemoryStream memStream = new MemoryStream()) 
   4:          { 
   5:              Stream compress = null; 
   6:  
   7:              // Choose the compression type and make the compression 
   8:              if (String.Equals(encodingType, "gzip", StringComparison.Ordinal)) 
   9:              { 
  10:                  compress = new GZipStream(memStream, CompressionMode.Compress); 
  11:              } 
  12:              else if (String.Equals(encodingType, "deflate", StringComparison.Ordinal)) 
  13:              { 
  14:                  compress = new DeflateStream(memStream, CompressionMode.Compress); 
  15:              } 
  16:              else 
  17:              { 
  18:                  // No compression 
  19:                  return buffer; 
  20:              } 
  21:  
  22:              compress.Write(buffer, 0, buffer.Length); 
  23:              compress.Dispose(); 
  24:  
  25:              return memStream.ToArray(); 
  26:          } 
  27:      } 

После чего вам остается лишь добавить сжатый поток в ответ пользователю:

   1: HttpContext.Response.OutputStream.Write(compressedData, 0, compressedData.Length);

Если же у вас есть доступ к IIS консоли, то вы можете настроить сжатие на уровне IIS(версии 7):

iis_compression1 

iis_compr2

Очистка JS и CSS кода

Также мы можем очистить наш css и js код от лишних символов.

Например, следующий css код

   1: body {
   2:   font-size:14px;
   3:   font-family:Arial;
   4: }
   5: h1 {
   6:   font-size:14px;
   7:   font-family:Arial;
   8: }

можно преобразовать в следующую строку

   1: body,h1{font:14px arial}
 

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

Для javascript кода наибольшей популярностью пользуются два инструмента JSMin (автор: Douglas Crockford) и Packer (автор: Dean Edward). Алгоритмы упаковки обоих инструментов обрабатывают(obfuscate) любой js код, но только при условии, что вы корректно завершаете все javascript-выражения символом “;” (включая объявление функций).

Для css кода вы можете воспользоваться утилитой под названием CSSTidy или одним из множества подобных онлайн-сервисов.

Оптимизация графики

Допустим в вашей базе данных, на жестком диске или любом другом хранилище расположена ваша любимая фотография размером 200x400 пикселей (24 Kb). Но вам необходимо отобразить ее на странице в виде изображения размером 100х200 пикселей. В таком случае, подобный код

   1: <img src="/images/mybestphoto.png" width="100" height="200" alt="My Best Photo" />

решит вашу проблему, но при этом размер вашей фотографии останется прежним - 24 Kb. Хотя, если бы вы сжали(изменили размер) ее в фотопопе, то "вес" файла существенно бы уменьшился.

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

   1: public void SaveResizedImage(string imagePath, int width, int height)
   2: {
   3:         int newResizeimageId;
   4:         // Читаем графический файл с жесткого диска
   5:         FileStream fs = File.OpenRead(imagePath);
   6:         byte[] data = new byte[fs.Length];
   7:         fs.Read(data, 0, data.Length);
   8:         MemoryStream ms = new MemoryStream(data);
   9:         Bitmap bmp = new Bitmap(ms);
  10:         System.Drawing.Image imgPhoto = (Image)bmp;
  11:         // Настраиваем Encoder, для преобразования графики
  12:         Encoder qualityEncoder = Encoder.Quality;
  13:         EncoderParameters parameterList = new EncoderParameters(1);
  14:         EncoderParameter qualityParameter = new EncoderParameter(qualityEncoder, 50L);
  15:         parameterList.Param[0] = qualityParameter;
  16:         // По расширению файла определяем кодек
  17:         ImageCodecInfo codec = GetCodecFromExtension(Path.GetExtension(imagePath)); //GetCodecFromExtension в этом листинге не приведена.
  18:         // Создаем пустую канву. Измененная графика будет записана в эту канву.
  19:         Bitmap bmPhoto = new Bitmap(width, height);
  20:         bmPhoto.SetResolution(10, 10);
  21:         Graphics grPhoto = Graphics.FromImage(bmPhoto);
  22:         grPhoto.SmoothingMode = SmoothingMode.HighSpeed;
  23:         grPhoto.InterpolationMode = InterpolationMode.High;
  24:         grPhoto.PixelOffsetMode = PixelOffsetMode.HighSpeed;
  25:         grPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, width, height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
  26:         // Сохраняем файл в память, а затем убеждаемся, что все ресурсы освобождены корректно.
  27:         MemoryStream mm = new MemoryStream();
  28:         bmPhoto.Save(mm, codec, parameterList);
  29:         imgPhoto.Dispose();
  30:         bmPhoto.Dispose();
  31:         grPhoto.Dispose();
  32:         //Сохраняем массив байт измененной графики куда необходимо. 
  33:         newResizeimageId = SaveImageToDb2(mm.GetBuffer());
  34:         mm.Dispose();
  35: }

Хочу обратить ваше внимание на строчку

   1: bmPhoto.SetResolution(10, 10);

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

avatar avatar_0 avatar_2 avatar_5 avatar_8
2.58 kB 2.86 kB (+10%) 1.98 kB
(-23%)
1.55 kB
(-39%)
672 bytes
(-74%)

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

Отключаем ViewState

Возможно вы подумали, о нехитром свойстве страницы EnableViewState="false". Отключение ViewState с помощью вышеупомянутого свойства действительно уменьшит размер скрытого поля, но не избавит вас от него. В отдельных случаях полезно и вовсе избавиться от ViewState. Сделать это можно, переопределив метод SavePageStateToPersistenceMedium, и “забыв” вызвать в нем базовый метод.

   1: protected override void SavePageStateToPersistenceMedium(object state) 
   2: { 
   3:         //base.SavePageStateToPersistenceMedium(state); 
   4: }

Избавляемся от длинных ID, сгенерированных ASP.NET

К сожалению, не существует способа избавиться от длинных ID в debug-версии вашего веб-сайта. Но когда ваш проект уже готов и скомпилирован, то вы можете обработать сборки, обфускатором. При этом, следует указать обфускатору заменять все имена контролов на более короткие. Таким образом вместо ctl00_body_WidgetPanelsLayout_WidgetContainer65_WidgetBodyPanel, ваша панель будет иметь id равное, например А. Будьте осторожны с подобной оптимизацией – ваш javascript код может не работать, если функционал привязан к заранее заданным ID. Хотя, если вы использовали что-то похожее на следующий код

   1: $get('<%= TextBox1.ClientID %>')

то обфускатор не нарушит вашего функционала.

Полезные ссылки

Reduce the weight of stylesheets by 35% at runtime

HTTP compression in ASP.NET 2.0

Compression and performance - GZip vs. Deflate

Compress your pages, css, js and WebResources.axd files for better performance

Online Tool compares Packer, JSMin, Dojo, and YUI Compressor

Speed Up Your Site: Optimize your CSS

CSS Optimization: Make Your Sites Load Faster for Free