Não importa

Devaneios de um DesDevOps

Tunning - Diminuindo o número de requisições com base64 encoding

Lendo esse artigo hoje, me lembrei que há algum tempo, mentalmente, comecei a escrever algo sobre quando usar e não usar a técnica que usa a imagem codificada em base64 para diminuir o número de requisições ao servidor. Antes de continuarmos, precisamos compreender por alto o que é o base64. Em termos gerais, base64 é uma forma de codificação para qualquer tipo de dado. Neste caso, nós podemos simplificar dizendo que a codificação base64 é a representação textual de uma imagem. Antes de mais nada, é bom lembrar que isso é uma técnica de tunning, e como em grande maioria delas, só é válida em alguns casos específicos. Por exemplo, essa técnica tem maiores ganhos somente quando existe uma quantidade considerável de imagens a serem carregadas em uma página.

Para continuarmos é necessário compreender um pouco sobre como é o passo do carregamento de uma página que contem vários itens a ser carregados. Considere o código abaixo para os próximos exemplos e explicações.

<!DOCTYPE html>
<html dir="ltr">
    <head>
        <meta charset="UTF-8" />
        <title>base64</title></title>
    <script type='text/javascript' src='js.js'></script>
    <link rel="stylesheet" href="css.css" type="text/css" media="screen" />
</head>
<body>
    <div class="image-list">
        <img src="imgs/01.jpg" />
        <img src="imgs/02.jpg" />
        <img src="imgs/03.jpg" />
        <img src="imgs/04.jpg" />
        <img src="imgs/05.jpg" />
        <img src="imgs/06.jpg" />
        <img src="imgs/07.jpg" />
        <img src="imgs/08.jpg" />
        <img src="imgs/09.jpg" />
        <img src="imgs/10.jpg" />
    </div>
</body>
</html>

O código é simples, mas consiste em doze requisições: Um arquivo de estilo, outro de javascript e mais dez requisições para cada imagem que será anexes-coada ao documento. Fiz com dez para não criar um arquivo monstruoso e não perder tempo. A primeira coisa que será carregada do documento acima será o arquivo javascript, mas o browser não pára para analizá-lo para depois depois ir para o próximo item, que seria o arquivo de estilo. Ao ler o documento, o browser vai fazer cada requisição de cada vez, o que pode ser perigoso, caso algum item do seu cabeçalho dê algum problema, o carregamento da sua página pode ser comprometido. Sabendo disso, que tal deixar a cargo do browser apenas duas requisições, e as outras dez serem feitas internamente pelo sistema operacional? Na prática, o que iremos fazer com essa técnica é pegar o conteúdo da imagem, criptografar em base64 e incluí-la no código fonte. A ferramenta de codificação e tradução base64 está implementada em diversas linguagens(python e ruby), e aqui neste exemplo vou utilizar em PHP.

O primeiro passo que irei fazer é codificar uma classe que me retorne a url codificada em base64 e que seja compatível com o que o browser espera. O formato é:

data:[<mime type>][;charset=<charset>][;base64],<encoded data>

c

<?php

final class DataUri {

  protected $file;

  public function __construct($file) {
    $this->file = $file;

    return $this;
  }

  public function generate() {
    if (file_exists($this->file)) {
      return $this->make_uri();
    } else {
      return false;
    }
  }

  private function make_uri() {
    return 'data:'
            . $this->get_mime()
            . ';base64,'
            . base64_encode(file_get_contents($this->file));
  }

  private function get_mime() {
    $info = new finfo(FILEINFO_MIME);

    return $info->file($this->file);
  }

}

$uri = new DataUri('./imgs/gluttony.jpg');
print $uri->generate();

O código acima, quando executado de forma correta, vai gerar as data uri no formato esperado. Veja o exemplo de uma uri gerada. Se você copiar e colar o código abaixo na sua barra de endereço, verá o resultado aqui.

Agora vamos criar o código que vai exibir todas as imagens de um determinado diretório e aplicar nossa técnica.

<?php require_once 'DataUri.php'; ?>
<!DOCTYPE html>
<html dir="ltr">
  <head>
    <meta charset="UTF-8" />
    <title>base64</title></title>
    <script type='text/javascript' src='js.js'></script>
    <link rel="stylesheet" href="css.css" type="text/css" media="screen" />
  </head>
  <body>
    <div class="image-list">
    <?php
      $dir = './imgs/';
      $iterator = new DirectoryIterator($dir);
      foreach ($iterator as $fileinfo) {
        if ($fileinfo->isFile()) {
          $uri = new DataUri($dir. $fileinfo->getFileName());
          echo '<img src="' . $uri->generate() . '" />' . PHP_EOL;
        }
      }
    ?>
    </div>
  </body>
</html>