Reaktionsfähiges Laden von Inhalten auf der Website

Hallo habr

Ich mache eine Website für mein Projekt. Auf der Seite muss man viele Gifs gleichzeitig zeigen, jedes wiegt ziemlich gut. Wenn Sie alles auf einmal anzeigen, wird die Seite sehr lange geladen. Gleichzeitig ist es auch unmöglich, die Seite ohne GIFs zu versehen (damit sie dort heruntergeladen werden können).

Wer sich dafür interessiert, wie ich mit diesem Problem umgegangen bin, frage ich nach einer Katze.

Eigentlich das Problem


Wie gesagt, es gibt SEHR viele GIFs auf der Website, gut und anders. Sie können selbst sehen, wie viele es sind: reface.tech

Bild

Sobald ich die Beta-Version der Landung sah, hatte ich sofort ein Problem mit dem Laden: Für einige Benutzer wurden die Seiten für eine lange Zeit geladen. Für ein ernstes Geschäft ist dies natürlich nicht der Fall.

Es war notwendig, das irgendwie zu lösen. Mit einer einfachen verlustfreien Komprimierung war es unmöglich auszukommen, da bereits zu diesem Zeitpunkt alle Medieninhalte über compressor.io gesteuert wurden. Daher war es notwendig, mit Verlusten zu komprimieren und GIFs mit schlechterer Qualität zu erhalten.

Schlechte Medieninhalte an Nutzer mit gutem Internet weiterzugeben, ist jedoch eine Art Sakrileg. Aus diesem Grund wurde beschlossen, die Geschwindigkeit Ihres Internets zu bestimmen und abhängig von der Geschwindigkeit die entsprechende Qualität auszuschalten.

Wir machen eine grobe Skizze


Wir werden ein Array mit einer Beschreibung des zu ladenden Medieninhalts haben.

Ein Beispiel:

[ { "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" } } ] 

Hier in der Elementik liegt für den entsprechenden Qualitätsgrad URL und Dateigröße.

Wir werden einfach:

  1. Gehen Sie das Array durch (beim Laden der Seite)
  2. Lesen Sie die Gesamtgröße, die für jeden Qualitätsgrad geladen wurde
  3. Bestimmen Sie, ob in 4 Sekunden alles geladen wird (das ist der Zeitraum, der mich persönlich stört)

Dementsprechend ist es notwendig:

  1. Habe so etwas gesehen, das so ein Array erstellt, dass bei Stiften nicht alles zählt (in Python)
  2. Sah Internet-Geschwindigkeit

Geschwindigkeitsmesser sägen


Es wird relativ einfach sein. Wir geben die Adresszeile Ihres Browsers ein eu.httpbin.org/stream-bytes/51200 . Eine Datei mit einer Länge von 51200 Bytes wird heruntergeladen. Wir schieben es uns in der Öffentlichkeit vor (um die Geschwindigkeit eines Hostings zu messen).

Jetzt müssen wir überprüfen, wie viel die Datei schwingt. Wir werden hierfür eine einfache Funktion einreichen, die die Geschwindigkeit in Megabyte pro Sekunde an uns zurückgibt.

 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); }); } 

Das heißt, wir haben die Startzeit des Downloads und die Endzeit aufgezeichnet und die Differenz gemessen. Da wir die Dateigröße kennen, haben wir sie einfach aufgeteilt.

Jetzt schreiben wir eine Funktion, die in dieser Geschwindigkeit etwas bewirkt:

 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; } } 

Im Allgemeinen liegt ein Problem mit diesem Code vor: Die genaue Verbindungsgeschwindigkeit wird aufgrund der geringen Dateigröße nicht bestimmt. Das Herunterladen von etwas mehr ist für uns jedoch zu teuer, sodass wir die resultierende Geschwindigkeit einfach mit 5 multiplizieren. Selbst mit einer Marge nehmen wir an, dass die Geschwindigkeit in Wirklichkeit sogar noch höher sein wird.

Jetzt legen wir eine Funktion ab, die abhängig von der Geschwindigkeit die entsprechende Qualität reduziert:

  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"; } } 

Da die Funktion, die die Geschwindigkeit zählt, asynchron zu uns ist, kann SpeedMeasure.speed Null sein. Standardmäßig glauben wir, dass die Verbindungsgeschwindigkeit 1 Megabyte pro Sekunde beträgt. Wenn die Funktion die Geschwindigkeit berechnet, rendern wir den Container einfach neu.

Wir übergeben ein Array von Arrays an die Funktion getResolution. Warum? Wenn wir mehrere Container auf der Seite haben, ist es für uns bequemer, den entsprechenden Inhalt auf jeden in einem Array zu übertragen, aber wir müssen die Download-Geschwindigkeit für alle gleichzeitig berücksichtigen.

Anwendungsbeispiel


Hier ist ein Anwendungsbeispiel (auf Reagieren):

  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> ); } 

Dementsprechend wird der Container beim Laden unserer Geschwindigkeitsbestimmung erneut gerendert.
Innerhalb des Containers (z. B. innerhalb von Control) entnehmen Sie einfach das entsprechende GIF aus dem Array (nach Index). Anschließend erhalten Sie ein Objekt nach Qualität und eine Referenz nach URL. Alles ist einfach.

Schreiben eines Python-Skripts


Jetzt müssen wir die Gifs irgendwie automatisch komprimieren und das Array mit der Beschreibung des Inhalts ausgeben.

Schreiben wir zunächst ein Skript für die Komprimierung. Wir werden Gifsicle verwenden. Bei Inhalten mit mittlerer Komprimierung beträgt die Komprimierungsstufe 80 (von 200), bei einer sehr leistungsstarken Funktion 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)) 

Um die Pfade zu den Dateien verständlich zu machen, folgt hier die Beschreibung des Dateiverzeichnisses mit GIFs:

  1. NOT_OPTIMIZED_DIR - nicht optimierte GIFs
  2. GIF_RESIZED_DIR - Nicht optimierte GIFs, deren Größe jedoch der Größe des Containers für sie entspricht
  3. GIF_COMPRESSED_DIR - komprimierte GIFs

In den Ordnern befinden sich Ordner mit GIF-Kategorienamen. In einem Ordner mit einem bestimmten Ordner enthält "groß", "mittel" und "klein" (unter den Arten von komprimierten Dateien).

Im Skript durchlaufen wir das Verzeichnis mit GIFs und führen für jede Datei zwei Komprimierungstypen durch, wobei der entsprechende Befehlszeilenbefehl aufgerufen wird.

Gehen wir nun zum Skript über, um ein Array mit Informationen zu erstellen.

 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)) 

Hier gehen wir die Ordner mit den Dateien durch, bestimmen die Dateigröße, ermitteln die Art der Komprimierung und geben die allgemeinen Informationen in das OUTPUT-Array ein. Und dann haben wir dieses Array wunderschön auf die Konsole ausgegeben, um es zu kopieren.

Fazit


Ich hoffe dieser Artikel hilft dir bei etwas. Habt eine nette Kodierung, Jungs.

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


All Articles