Отдача мелкой графики

в 4:20, , рубрики: image, javascript, php, sqlite, Веб-разработка, Клиентская оптимизация, метки: , , ,

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

Понятно, что хранить в базе большие картинки смысла нет. Причин тому много, и все они уже давно всем известны, FileStream пока не рассматриваем. Однако часто возникает задача отдавать с одной страницы большое количество всякой мелочи – например аватарки в блогах или соцсетях, картинки-превью к новостям в лентах, и т.д., т.е. относительно лёгкую графику, но в товарных количествах. Беда в том, что отдача каждой такой картинки создаёт отдельный коннект к серверу, в итоге загрузка одной страницы порождает несколько десятков запросов на отдачу всякой мелюзги, общий объём которой на странице не превышет может быть сотни килобайт. Для нынешних каналов это ничто, а вот куча запросов к серверу при рендеринге страницы – это плохо.

Довольно интересным представляется решение, при котором вся эта мелочь пузатая будет отдаваться в один поток. Таким образом мы на порядок снижаем количество запросов к серверу, а значит повышаем стойкость сайта к DDoS-атакам. В качестве приятного бонуса – перспектива прокачать юзабилити: все картинки будут возникать на странице сразу (без эффекта «подгрузки»), одновременно и без «дырок». Небольшая пауза перед их появлением не в счёт, субъективно такая загрузка выглядит «шустрее».

Видится примерно такая схема: в тексте HTML-файла ставятся плейсхолдеры с ID, соответстветствующими картикам в базе. Javascript «пробегает» по плейсхолдерам и формирует строку XMLHTTP-запроса, в ответ на который сервер возвращает массив base64-закодированных строк, которые опять же джаваскрипт рассовывает по src соответствующих плейсхолдеров.

В итоге вместо получения пары десятков отдельных картинок весом по 2-5кБ мы получаем JSON-строку объёмом 50-100кБ за один асинхронный запрос. То есть а) уже ПОСЛЕ того, как прогрузится и отрендерится основной текстовый контент, и б) гораздо быстрее за счёт особенностей стриминга текстовых данных.

Рабочий пример (аватарки надёрганы из сети).

Код можно посмотреть в исходнике страницы. Сервлет на PHP (работает с SQLite) выглядит так:

<?
ob_start();

$dbh = sqlite_open('data/img', 0666, $sqliteerror);
$sth = sqlite_query($dbh, "SELECT *, ROWID AS id FROM img WHERE ROWID IN (".trim($_GET['q']).") LIMIT 20");
$res = sqlite_fetch_all($sth, SQLITE_ASSOC);

echo json_encode($res);

sqlite_close($dbh);
ob_end_flush();
?>

Что скажете, совсем дурацкая идея? Или я велосипед изобрёл?

Автор: gregory_777

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js