Fazendo o carregamento de conteúdo responsivo no site

Olá Habr!

Estou criando um site para o meu projeto. No site, você precisa mostrar muitos gifs ao mesmo tempo, cada um pesando muito bem. Se você mostrar tudo de uma vez, a página será carregada por um período muito longo. Ao mesmo tempo, é impossível fornecer a página sem GIFs (para que possam ser baixados lá).

Quem estiver interessado em como eu lidei com esse problema, peço um gato.

Na verdade, o problema


Como eu disse, existem MUITOS gifs no site, bons e diferentes. Você pode ver por si mesmo quantos deles: reface.tech

imagem

Assim que vi a versão beta do pouso, tive imediatamente um problema com o carregamento: para alguns usuários, as páginas estavam carregando por um longo tempo. Para um negócio sério, é claro que não é esse o caso.

Era necessário resolver isso de alguma forma. Era impossível sobreviver com a simples compactação sem perdas, pois já naquele tempo todo o conteúdo da mídia já havia sido conduzido pelo compressor.io . Portanto, era necessário comprimir com perdas e dar GIFs com pior qualidade.

Mas divulgar conteúdo de mídia ruim para usuários com boa Internet é uma espécie de sacrilégio. Portanto, foi decidido determinar de alguma forma a velocidade da sua Internet e dependendo da velocidade para diminuir a qualidade apropriada.

Nós fazemos um esboço


Teremos uma matriz com uma descrição do conteúdo da mídia a ser carregada.

Um exemplo:

[ { "large": { "size": 0.6211118698120117, "url": "gifs/control/large/control_1.gif" }, "middle": { "size": 0.5330495834350586, "url": "gifs/control/middle/control_1.gif" }, "small": { "size": 0.4901447296142578, "url": "gifs/control/small/control_1.gif" } } ] 

Aqui, no básico para o grau adequado de qualidade, estão o URL e o tamanho do arquivo.

Simplesmente:

  1. Percorra a matriz (ao carregar a página)
  2. Leia o tamanho total carregado para cada grau de qualidade
  3. Determine se ele carregará tudo em 4 segundos (este é o período que me incomoda pessoalmente)

Por conseguinte, é necessário:

  1. Vi algum tipo de coisa que criará uma matriz para que tudo não conte com canetas (em python)
  2. Vi a velocidade da Internet

Serrar o medidor de velocidade


Será relativamente simples. Digitamos na barra de endereço do seu navegador eu.httpbin.org/stream-bytes/51200 . Um arquivo com um comprimento de 51200 bytes é baixado. Nós o empurramos para nós mesmos em público (para medir a velocidade de uma hospedagem).

Agora precisamos verificar quanto o arquivo oscila. Arquivaremos uma função simples para isso, que retornará a velocidade em megabytes por segundo para nós.

 async checkDownloadSpeed(baseUrl, fileSizeInBytes) { return new Promise((resolve, _) => { let startTime = new Date().getTime(); return axios.get(baseUrl).then( response => { const endTime = new Date().getTime(); const duration = (endTime - startTime) / 1000; const bytesPerSecond = (fileSizeInBytes / duration); const megabytesPerSecond = (bytesPerSecond / 1000 / 1000); resolve(megabytesPerSecond); }); }).catch(error => { throw new Error(error); }); } 

Ou seja, registramos o horário de início do download, o horário de término, medimos a diferença e, como sabemos o tamanho do arquivo, simplesmente o dividimos.

Agora, escreveremos uma função que fará algo nessa velocidade específica:

 async getNetworkDownloadSpeed() { const baseUrl = process.env.PUBLIC_URL + '/51200'; const fileSize = 51200; const speed = await this.checkDownloadSpeed(baseUrl, fileSize); console.log("Network speed: " + speed); if (speed.mbps === "Infinity") { SpeedMeasure.speed = 1; } else { SpeedMeasure.speed = speed * 5; } } 

Em geral, há um problema com este código: é que a velocidade exata da conexão não é determinada devido ao tamanho pequeno do arquivo. Mas baixar algo mais é muito caro para nós, então simplesmente multiplicamos a velocidade resultante por 5. Mesmo com uma margem, nós a aceitamos, porque, na realidade, a velocidade será ainda maior.

Agora arquivaremos uma função que, dependendo da velocidade, reduzirá a qualidade correspondente:

  static getResolution(gifsArray) { let totalSizeLevel1 = 0; let totalSizeLevel2 = 0; let totalSizeLevel3 = 0; for (let i = 0; i < gifsArray.length; i++) { for (let a = 0; a < gifsArray[i].length; a++) { let element = gifsArray[i][a]; totalSizeLevel1 += element.small.size; totalSizeLevel2 += element.middle.size; totalSizeLevel3 += element.large.size; } } if (isNaN(SpeedMeasure.speed)) { SpeedMeasure.speed = 1; } let timeLevel1 = totalSizeLevel1 / SpeedMeasure.speed; let timeLevel2 = totalSizeLevel2 / SpeedMeasure.speed; let timeLevel3 = totalSizeLevel3 / SpeedMeasure.speed; if (timeLevel3 < APPROPRIATE_TIME_LIMIT) { return "large"; } else if (timeLevel2 < APPROPRIATE_TIME_LIMIT) { return "middle"; } else { return "small"; } } 

Como a função que conta a velocidade é assíncrona para nós, o SpeedMeasure.speed pode ser zero. Por padrão, acreditamos que a velocidade da conexão é de 1 megabyte por segundo. Quando a função calcula a velocidade, apenas renderizamos novamente o contêiner.

Passamos uma matriz de matrizes para a função getResolution. Porque Como se tivermos vários contêineres na página, é mais conveniente transferir o conteúdo correspondente para cada um deles em uma matriz, mas precisamos considerar a velocidade do download de uma só vez.

Exemplo de uso


Aqui está um exemplo de uso (em React):

  async runFunction() { let speedMeasure = new SpeedMeasure(); await speedMeasure.getNetworkDownloadSpeed(); this.forceUpdate() } componentDidMount() { this.runFunction(); } render() { let quality = SpeedMeasure.getResolution([ Control.getControlArray(), Health.getHealthArray() ]); return ( <div className="app"> <Presentation /> <Control quality={quality} /> <Health quality={quality} /> </div> ); } 

Assim, quando nossa determinação de velocidade é carregada, o contêiner será renderizado novamente.
Dentro do contêiner (por exemplo, dentro de Control), você apenas pega o GIF correspondente da matriz (por índice), obtém um objeto por qualidade e obtém um link por URL. Tudo é simples.

Escrevendo um script Python


Agora, precisamos de alguma forma compactar automaticamente os gifs e gerar a matriz com a descrição do conteúdo.

Para começar, vamos escrever um script para compactação. Vamos usar gifsicle. Para conteúdo de compactação média, o nível de compactação será 80 (em 200), para um recurso muito poderoso será 160.

 import os GIFS_DIR = "/home/mixeden//Landingv2/" COMPRESSOR_DIR = "/home/mixeden//gifsicle-static" NOT_OPTIMIZED_DIR = "not_optimized" OPTIMIZED_DIR = "optimized" GIF_RESIZED_DIR = "gif_not_optimized_resized" GIF_COMPRESSED_DIR = "gif_compressed" COMPRESSION_TYPE = ["middle", "small"] for (root, dirs, files) in os.walk(GIFS_DIR, topdown=True): if len(files) > 0 and GIF_RESIZED_DIR in root: for file in files: path = root + "/" + file for compression in COMPRESSION_TYPE: final_path = path.replace(GIF_RESIZED_DIR, GIF_COMPRESSED_DIR + "/" + compression + "/" + OPTIMIZED_DIR) print(path, final_path) if compression == COMPRESSION_TYPE[0]: rate = 80 else: rate = 160 os.system("echo 0 > " + final_path) os.system(COMPRESSOR_DIR + " -O3 --lossy={} -o {} {}".format(rate, final_path, path)) 

Para tornar os caminhos dos arquivos compreensíveis, eis a descrição do diretório de arquivos com gifs:

  1. NOT_OPTIMIZED_DIR - GIFs não otimizados
  2. GIF_RESIZED_DIR - GIFs não otimizados, mas redimensionados de acordo com o tamanho do contêiner para eles
  3. GIF_COMPRESSED_DIR - GIFs compactados

Dentro das pastas, existem pastas com nomes de categorias GIF. Dentro de uma pasta com uma pasta específica contém "grande", "médio" e "pequeno" (nos tipos de arquivos compactados).

No script, passamos pelo diretório com gifs e, para cada arquivo, fazemos dois tipos de compactação, chamando o comando de linha de comando correspondente.

Agora vamos ao script para criar uma matriz com informações.

 import json import os GIFS_DIR = "/home/mixeden//Landingv2/" COMPRESSOR_DIR = "/home/mixeden//gifsicle-static" NOT_OPTIMIZED_DIR = "not_optimized" OPTIMIZED_DIR = "optimized" GIF_RESIZED_DIR = "gif_not_optimized_resized" GIF_COMPRESSED_DIR = "gif_compressed" COMPRESSION_TYPE = ["large", "middle", "small"] OUTPUT = {} for (root, dirs, files) in os.walk(GIFS_DIR, topdown=True): if len(files) > 0 and GIF_COMPRESSED_DIR in root and NOT_OPTIMIZED_DIR not in root: files.sort() type = root.split(GIFS_DIR)[1].split(GIF_COMPRESSED_DIR)[0].replace("/", "") print(type) if type not in OUTPUT: OUTPUT[type] = [] if len(OUTPUT[type]) == 0: for file in files: OUTPUT[type].append( { "large": { "url": "", "size": 0 }, "middle": { "url": "", "size": 0 }, "small": { "url": "", "size": 0 } }) for file in files: full_path = root + "/" + file bytes_size = os.path.getsize(full_path) kilobytes_size = bytes_size / 1000 megabytes_size = kilobytes_size / 1000 index = int(file.split("_")[1].replace(".gif", "")) - 1 for typer in COMPRESSION_TYPE: if typer in root: local_type = typer new_url = "gifs/" + full_path.replace(GIFS_DIR, "").replace("/" + GIF_COMPRESSED_DIR, "").replace("/" + OPTIMIZED_DIR, "") OUTPUT[type][index][local_type]['url'] = new_url OUTPUT[type][index][local_type]['size'] = megabytes_size print(OUTPUT) print(json.dumps(OUTPUT, indent=4, sort_keys=True)) 

Aqui, examinamos as pastas com os arquivos, determinamos o tamanho do arquivo, descobrimos o tipo de compactação e colocamos as informações gerais na matriz OUTPUT. E então produzimos essa matriz no console para copiá-la.

Conclusão


Espero que este artigo ajude você com alguma coisa. Tenha uma boa codificação, pessoal.

Source: https://habr.com/ru/post/pt480704/


All Articles