Heim > Web-Frontend > js-Tutorial > Dynamische Bildgestaltung mit Servicemitarbeitern

Dynamische Bildgestaltung mit Servicemitarbeitern

Patricia Arquette
Freigeben: 2024-11-19 18:00:04
Original
256 Leute haben es durchsucht

Servicemitarbeiter sind eine fantastische Technologie. Sie kennen sie möglicherweise im Zusammenhang mit dem Begriff Progressive Web Application (PWA), sodass etwas, das normalerweise im Browser sichtbar ist, im Betriebssystem „installiert“ und wie eine native Anwendung geöffnet und wie eine native Anwendung deinstalliert werden kann. und sieht rundum wie eine native Anwendung aus. Aber Servicemitarbeiter können noch viel mehr.

Dynamic image creation with service workers

Zugänglichkeit und Erläuterungen finden Sie hier.

Service Worker sind im Grunde geteilte Web Worker (die übrigens als separate Technologie existieren) mit der besonderen Fähigkeit, alle HTTP-Anfragen abzufangen, die der Browser von URLs im gleichen Bereich stellt (Ursprungspfad), bei dem der Worker registriert wurde. Dann könnte er angewiesen werden, entweder mit einer konstruierten oder zwischengespeicherten Antwort zu antworten – was tatsächlich verhindert, dass der Browser das Netzwerk mit der Anfrage erreicht – oder die Anfrage ganz normal oder durch Modifizieren der Anfrage (mit Fetch) an das Netzwerk weiterzuleiten.

Vor diesem Hintergrund ist klar, warum Servicemitarbeiter häufig mit der Fähigkeit in Verbindung gebracht werden, auf eine Webseite zuzugreifen, wenn sie offline sind: Beim ersten Mal können Sie alle statischen Ressourcen herunterladen und zwischenspeichern (was im Grunde „installiert“ wird). der Seite), dann kann der Servicemitarbeiter mit den zwischengespeicherten Versionen auf dieselben Anfragen antworten und dabei im Grunde die „Anwendungsressourcen“ bereitstellen, als wäre es eine native App. dev.to ist ein großartiges Beispiel dafür.

Dies ist bereits eine Vereinfachung, und über Cache-Busting, Aktualisierungen und den Rest zu sprechen, würde den Rahmen dieses Artikels sprengen, daher werde ich mich darauf nicht einlassen. Worüber ich sprechen werde, ist die Fähigkeit von Servicemitarbeitern, konstruierte Antworten zu liefern.

Spöttische Antworten

Mein Team wurde kürzlich damit beauftragt, eine „Showcase“-Anwendung zu erstellen, d. h. eine Webanwendung, die im Grunde nichts tut, sondern dem Zweck dient, zu zeigen, wie unser Web Component UI Kit gemäß dem Designsystem verwendet wird und die Kodierungsrichtlinien.

Die Anwendung war als reine Frontend-Anwendung gedacht (das heißt, wir sollten nicht auch ein Backend entwickeln), sollte aber aussehen wie eine der vielen B2B-Anwendungen, die unser Kunde verwaltet, mit Backend und allem . Hier bietet sich die Rolle eines Servicemitarbeiters an.

Jetzt ist es ganz einfach, mit einer Textantwort zu antworten. Sogar ein JSON ist im Grunde Text, also könnte unser Servicemitarbeiter am Ende etwa so aussehen:

self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/hello')) {
    event.respondWith(new Response(
      JSON.stringify({ message: 'Hello!' }),
      { headers: { 'Content-Type': 'application/json' }}
    );
  } else  {
    event.respondWith(fetch(event.request));
  }
});
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Ich werde Sie nicht damit langweilen, wie dieses Snippet verbessert werden könnte. Der URL-Abgleich könnte URLPattern verwenden. Sie können statische Daten mit fetch laden und auf IndexedDB speichern. Da kann man verrückt werden.

Aber was ist mit anderen Arten dynamischer Reaktionen? Mögen Sie Bilder?

Bilder erzeugen: der „einfache“ Weg.

Der einfachste Weg, ein dynamisches Bild zu generieren, ist die Erstellung einer SVG-Datei, bei der es sich im Grunde um ein XML-Dokument handelt. Das heißt, es ist Text. Das ist eine durchaus machbare Aufgabe, und Sie können Bibliotheken wie D3.js verwenden, um die SVG-Elemente und -Pfade für Sie zu generieren: Fabriken wie line() und andere geben Funktionen zurück, die das zurückgeben, was Sie in das d-Attribut von einfügen müssen. Elemente:

self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/hello')) {
    event.respondWith(new Response(
      JSON.stringify({ message: 'Hello!' }),
      { headers: { 'Content-Type': 'application/json' }}
    );
  } else  {
    event.respondWith(fetch(event.request));
  }
});
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Das dynamische Generieren von SVGs könnte großartig sein, um die Aufgabe vom Hauptthread zu lösen – und das Ergebnis könnte sogar zwischengespeichert werden. Dies eignet sich hervorragend für Diagramme und Infografiken und ist „einfach“ genug, um es zu bewerkstelligen.

Generieren anderer Bildtypen

Schwieriger ist es, ein Rasterbild wie ein PNG- oder JPG-Bild zu erstellen. „Generieren“ bedeutet, ein Bild mithilfe von Bearbeitungsinstrumenten zu verändern oder von Grund auf neu zu erstellen. In diesen Fällen verwenden wir normalerweise eine Element, holen Sie sich seinen 2D-Kontext und beginnen Sie mit dem Malen darauf, indem Sie seine vielen Zeichenanweisungen verwenden.

Das Problem besteht darin, dass Servicemitarbeiter keinen Zugriff auf das DOM-Element haben. Also, haben wir kein Glück?

Keine Sorge, meine Freunde! Weil alle Mitarbeiter (einschließlich Servicemitarbeiter) OffscreenCanvas-Objekte erstellen können. Geben Sie dem Konstruktor eine Breite und eine Höhe in Pixeln ein und schon haben Sie eine vollkommen feine (wenn auch unsichtbare) Leinwand in einem Service-Worker:

import { pie, arc } from 'd3-shape';

const pieData = pie().sort(null)(data);
const sectorArc = arc().outerRadius(35).innerRadius(20);

const svg = '<svg viewBox="-40 -40 80 80" xmlns="http://www.w3.org/2000/svg">'
  + pieData.map((pie, index) =>
    `<path d="${sectorArc(pie)}" fill="${colors[index]}"/>`
  ).join('')
  + '</svg>';

event.respondWith(new Response(
  svg, { headers: { 'Content-Type': 'image/svg+xml' }}
));
Nach dem Login kopieren
Nach dem Login kopieren

Für diejenigen, die sich fragen: Ja, Sie können eine andere Art von Kontext erhalten, obwohl nicht alle davon in jedem Browser verfügbar sind. Sie können versuchen, eine Bibliothek wie three.js zu verwenden, um 3D-Szenen in einem Service Worker zu generieren (ich denke, das werde ich später versuchen).

Jetzt können wir im Grunde alles tun. Zeichnen Sie Linien, Bögen, Pfade usw. und ändern Sie sogar die Geometrie unserer Leinwand. Das ist so einfach wie das Zeichnen in einem DOM-Canvas-Kontext, daher werde ich mich diesem Teil nicht widmen.

Zeichnungstext

Wir können tatsächlich auch Texte schreiben. Dies ist wichtig, da wir das in anderen Umgebungen – nämlich einem Paint-Worklet – nicht tun können:

Hinweis: Der PaintRenderingContext2D implementiert eine Teilmenge der CanvasRenderingContext2D-API. Insbesondere werden die APIs CanvasImageData, CanvasUserInterface, CanvasText oder CanvasTextDrawingStyles nicht implementiert.

Aber bei einem Servicemitarbeiter ist das alles in Ordnung. Das bedeutet, dass wir über eine leistungsfähigere (wenn auch weniger leistungsfähige) Umgebung zum Generieren unserer Hintergrundbilder verfügen.

So einfach können Sie Text zeichnen:

const canvas = new OffscreenCanvas(800, 600);
const context = canvas.getContext('2d');
Nach dem Login kopieren
Nach dem Login kopieren

Sie können hier die Schriftart verwenden, die Ihnen gefällt, aber ich habe festgestellt, dass übliche Standardwerte wie Sans-Serif, Monospace oder System-UI nicht zu funktionieren scheinen, da sie alle auf sie zurückgreifen die Standard-Serifenschrift. Aber Sie können Schriftartenstapel wie gewohnt verwenden:

context.fillStyle = '#222';
context.font = '24px serif';
// (x, y) = (50, 90) will be the *bottom left* corner of the text
context.fillText('Hello, world!', 50, 90);
Nach dem Login kopieren

Darüber hinaus können Sie die Font Loading API verwenden, um Schriftarten von externen Ressourcen zu laden:

self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/hello')) {
    event.respondWith(new Response(
      JSON.stringify({ message: 'Hello!' }),
      { headers: { 'Content-Type': 'application/json' }}
    );
  } else  {
    event.respondWith(fetch(event.request));
  }
});
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Zurücksenden an die Bewerbung

Das Zurücksenden der Antwort ist wiederum so einfach wie der Aufruf der Methode „convertToBlob“, die das Versprechen eines – Sie haben es erraten – eines Blobs zurückgibt. Und Blobs können problemlos an den Absender zurückgesendet werden.

import { pie, arc } from 'd3-shape';

const pieData = pie().sort(null)(data);
const sectorArc = arc().outerRadius(35).innerRadius(20);

const svg = '<svg viewBox="-40 -40 80 80" xmlns="http://www.w3.org/2000/svg">'
  + pieData.map((pie, index) =>
    `<path d="${sectorArc(pie)}" fill="${colors[index]}"/>`
  ).join('')
  + '</svg>';

event.respondWith(new Response(
  svg, { headers: { 'Content-Type': 'image/svg+xml' }}
));
Nach dem Login kopieren
Nach dem Login kopieren

Die Methode erstellt standardmäßig ein PNG-Bild, könnte aber auch angewiesen werden, stattdessen eine JPG-Datei zu erstellen, wie oben gezeigt. „image/webp“ ist ein weiteres gängiges Format, das jedoch von Safari nicht unterstützt wird. Um ehrlich zu sein, ist die Auswahl hier etwas enttäuschend, da neu verfügbare und leistungsfähigere Bildformat-Decoder nicht in den entsprechenden Encodern widergespiegelt werden. Aber das reicht für die meisten Zwecke sowieso aus.

Unterhaltsame Tatsache: Die Methode „convertToBlob“ ist spezifisch für die OffscreenCanvas-Klasse. HTMLCanvasElements verfügen stattdessen über toBlob, das einen Rückruf als erstes Argument akzeptiert, im üblichen Stil der asynchronen Aufgabenbearbeitung vor der Promise-Ära.

Verwendung eines Vorlagenbildes

Das alles funktioniert nun, wenn wir ein Bild von Grund auf erstellen möchten. Aber was ist, wenn wir mit einer leeren Vorlage beginnen möchten?

Wenn wir im Haupt-Thread arbeiten würden, könnten wir mithilfe der drawImage-Methode unseres 2D-Kontexts ein Bild in den Kontext einfügen und es z. von einem leicht verfügbaren Element.

Das Problem ist wiederum, dass wir nicht auf das DOM zugreifen können, sodass wir nicht auf verweisen können. Elemente. Stattdessen können wir das Bild abrufen, das wir als Hintergrund benötigen, seinen Blob abrufen und ihn dann in etwas anderes umwandeln, das drawImage verarbeiten kann. Geben Sie createImageBitmap ein, eine globale Methode, die auch in Service Workern verfügbar ist. Es gibt ein Versprechen für eine ImageBitmap-Instanz zurück, eine der vielen weniger bekannten Klassen der Frontend-Webentwicklung. Es wird offenbar häufiger in WebGL-Kontexten verwendet, aber drawImage scheint es zu akzeptieren, also...

const canvas = new OffscreenCanvas(800, 600);
const context = canvas.getContext('2d');
Nach dem Login kopieren
Nach dem Login kopieren

Von diesem Punkt an können wir damit fortfahren, unsere Kritzeleien und Texte darauf zu zeichnen und so ein zufriedenstellendes synamisches Bild zu erstellen, das wir an den Benutzer zurücksenden können.

Hinweis: Dies könnte mit einer SVG-Datei einfacher gelöst werden, da Sie einfach ein Element zum Einrichten eines Hintergrundbilds. Das würde aber bedeuten, dass der Browser das Bild laden muss, nachdem das generierte Bild gesendet wurde, während dies bei dieser Technik vor erfolgt. Ähnliches gilt für die Auswahl einer Schriftart.

Alles zusammenfügen

In all diesen Beispielen habe ich Modul Service Worker verwendet (d. h. ich habe den Import aus anderen ES-Modulen verwendet). Leider werden Modul-Servicemitarbeiter noch nicht von Firefox unterstützt, aber hoffentlich bald. In der Zwischenzeit müssen Sie möglicherweise Ihren Code anpassen, um stattdessen die alten ImportScripts zu verwenden.

Bedenken Sie beim Importieren anderer Skripts in einen Service Worker, entweder über import oder importScripts, dass der Browser kein ein Updatefound-Ereignis auslöst, wenn sich eine importierte Datei ändert: Es wird nur dann ausgelöst Das Service-Worker-Eingabeskript ändert sich.

In einem Fall wie unserem, in dem der Servicemitarbeiter nur benötigt wird, um die Anwesenheit eines Backends vorzutäuschen, könnte sein Lebenszyklus verkürzt werden, indem self.skipWaiting() genau dann aufgerufen wird, wenn das Installationsereignis ausgelöst wird, und dann self aufgerufen wird. client.claim() beim Aktivierungsereignis, um sofort auf Anfragen reagieren zu können (andernfalls startet es erst bei der nächsten Seitenaktualisierung).

self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/hello')) {
    event.respondWith(new Response(
      JSON.stringify({ message: 'Hello!' }),
      { headers: { 'Content-Type': 'application/json' }}
    );
  } else  {
    event.respondWith(fetch(event.request));
  }
});
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Und das ist im Grunde alles, also... viel Spaß mit den Servicemitarbeitern, Leute!

Das obige ist der detaillierte Inhalt vonDynamische Bildgestaltung mit Servicemitarbeitern. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage