Fermer

avril 28, 2025

Construire un système de téléchargement d’images convivial hors ligne

Construire un système de téléchargement d’images convivial hors ligne


Une mauvaise connectivité Internet ne doit pas signifier une mauvaise UX. Avec des technologies PWA comme IndexedDBles travailleurs du service et l’API de synchronisation des antécédents, vous pouvez créer un système de téléchargement d’image convivial hors ligne qui fait la file d’attente qui les télécharge et les réchauffe automatiquement – afin que vos utilisateurs puissent télécharger sans contrainte, même lorsqu’ils sont hors ligne.

Ainsi, vous remplissez un formulaire en ligne et il vous demande de télécharger un fichier. Vous cliquez sur l’entrée, sélectionnez un fichier sur votre bureau et êtes bon à y aller. Mais quelque chose se passe. Le réseau tombe, le fichier disparaît et vous êtes coincé à re-télécharger le fichier. Mauvaise connectivité réseau Peut vous conduire à passer un temps déraisonnable à essayer de télécharger des fichiers avec succès.

Ce qui ruine l’expérience utilisateur résulte d’avoir à vérifier constamment la stabilité du réseau et à réessayer le téléchargement plusieurs fois. Bien que nous ne puissions pas faire grand-chose à faire beaucoup sur la connectivité réseau, en tant que développeurs, nous pouvons toujours faire quelque chose pour soulager la douleur qui vient avec ce problème.

L’une des façons de résoudre ce problème est de modifier les systèmes de téléchargement d’images d’une manière qui permet aux utilisateurs de télécharger des images hors ligne – Éliminer le besoin d’une connexion réseau fiablepuis le fait que le système réessaye le processus de téléchargement lorsque le réseau devient stable, sans que l’utilisateur n’intervient.

Cet article va se concentrer sur l’explication de la façon de construire Un système de téléchargement d’image convivial hors ligne Utilisation de technologies PWA (Application Web progressive) telles que IndexedDBles travailleurs du service et l’API de synchronisation de fond. Nous couvrirons également brièvement des conseils pour améliorer l’expérience utilisateur de ce système.

Planification du système de téléchargement d’image hors ligne

Voici un tableau de flux pour un système de téléchargement d’images convivial hors ligne.

Tableau de flux d'un système de téléchargement d'image convivial hors ligne
Tableau de débit d’un système de téléchargement d’images convivial (Grand aperçu)

Comme indiqué dans le graphique de flux, le processus se déroule comme suit:

  1. L’utilisateur sélectionne une image.
    Le processus commence par laisser l’utilisateur sélectionner son image.
  2. L’image est stockée localement dans IndexedDB.
    Ensuite, le système vérifie la connectivité réseau. Si la connectivité réseau est disponible, le système télécharge directement l’image, en évitant l’utilisation de stockage locale inutile. Cependant, si le réseau n’est pas disponible, l’image sera stockée dans IndexedDB.
  3. Le travailleur de service détecte lorsque le réseau est restauré.
    Avec l’image stockée dans IndexedDBle système attend pour détecter quand la connexion réseau est restaurée pour continuer avec l’étape suivante.
  4. La synchronisation de l’arrière-plan traite les téléchargements en attente.
    Au moment où la connexion est restaurée, le système essaiera de télécharger à nouveau l’image.
  5. Le fichier est téléchargé avec succès.
    Au moment où l’image est téléchargée, le système supprimera la copie locale stockée dans IndexedDB.

Implémentation du système

La première étape de l’implémentation du système permet à l’utilisateur de sélectionner ses images. Il existe différentes façons d’y parvenir:

  • Vous pouvez utiliser un simple <input type="file"> élément;
  • Une interface glisser-déposer.

Je vous conseille d’utiliser les deux. Certains utilisateurs préfèrent utiliser l’interface glisser-déposer, tandis que d’autres pensent que la seule façon de télécharger des images est via le <input type="file"> élément. Avoir les deux options aidera à améliorer l’expérience utilisateur. Vous pouvez également envisager de permettre aux utilisateurs de coller des images directement dans le navigateur à l’aide de l’API du presse-papiers.

Enregistrer le fonctionnaire

Au cœur de cette solution se trouve le employé de service. Notre travailleur de service va être responsable de la récupération de l’image de la IndexedDB stocker, le télécharger lorsque la connexion Internet est restaurée et effacer le IndexedDB Conservez lorsque l’image a été téléchargée.

Pour utiliser un employé de service, vous devez d’abord en enregistrer un:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js')
    .then(reg => console.log('Service Worker registered', reg))
    .catch(err => console.error('Service Worker registration failed', err));
}

Vérification de la connectivité réseau

N’oubliez pas que le problème que nous essayons de résoudre est causé par Connectivité réseau peu fiable. Si ce problème n’existe pas, il est inutile d’essayer de résoudre quoi que ce soit. Par conséquent, une fois l’image sélectionnée, nous devons vérifier si l’utilisateur a une connexion Internet fiable avant d’enregistrer un événement de synchronisation et de stocker l’image dans IndexedDB.

function uploadImage() {
  if (navigator.onLine) {
    // Upload Image
  } else {
    // register Sync Event
    // Store Images in IndexedDB
  }
}

Note: J’utilise seulement le navigator.onLine propriété ici pour démontrer comment le système fonctionnerait. Le navigator.onLine la propriété est peu fiableet je vous suggère de trouver une solution personnalisée pour vérifier si l’utilisateur est connecté à Internet ou non. Une façon de le faire est d’envoyer une demande de ping à un point de terminaison de serveur que vous avez créé.

Enregistrement de l’événement Sync

Une fois le test réseau échoué, l’étape suivante consiste à enregistrer un événement de synchronisation. L’événement Sync doit être enregistré au point où le système ne télécharge pas l’image en raison d’une mauvaise connexion Internet.

async function registerSyncEvent() {
  if ('SyncManager' in window) {
    const registration = await navigator.serviceWorker.ready;
    await registration.sync.register('uploadImages');
    console.log('Background Sync registered');
  }
}

Après avoir enregistré l’événement de synchronisation, vous devez l’écouter dans le travailleur des services.

self.addEventListener('sync', (event) => {
  if (event.tag === 'uploadImages') {
    event.waitUntil(sendImages());
  }
});

Le sendImages La fonction va être un processus asynchrone qui récupérera l’image à partir de IndexedDB et le télécharger sur le serveur. C’est à quoi ça va ressembler:

async function sendImages() {
  try {
    // await image retrieval and upload
  } catch (error) {
    // throw error
  }
}

Ouverture de la base de données

La première chose que nous devons faire pour stocker notre image localement est d’ouvrir un IndexedDB magasin. Comme vous pouvez le voir dans le code ci-dessous, nous créons Une variable globale pour stocker l’instance de base de données. La raison de cela est que, par la suite, lorsque nous voulons récupérer notre image à partir de IndexedDBnous n’aurions pas besoin d’écrire le code pour ouvrir à nouveau la base de données.

let database; // Global variable to store the database instance

function openDatabase() {
  return new Promise((resolve, reject) => {
    if (database) return resolve(database); // Return existing database instance 

    const request = indexedDB.open("myDatabase", 1);

    request.onerror = (event) => {
      console.error("Database error:", event.target.error);
      reject(event.target.error); // Reject the promise on error
    };

    request.onupgradeneeded = (event) => {
        const db = event.target.result;
        // Create the "images" object store if it doesn't exist.
        if (!db.objectStoreNames.contains("images")) {
          db.createObjectStore("images", { keyPath: "id" });
        }
        console.log("Database setup complete.");
    };

    request.onsuccess = (event) => {
      database = event.target.result; // Store the database instance globally
      resolve(database); // Resolve the promise with the database instance
    };
  });
}

Stockage de l’image dans IndededDB

Avec IndexedDB Stockage ouvert, nous pouvons maintenant stocker nos images.

Maintenant, vous vous demandez peut-être pourquoi une solution plus facile comme localStorage n’a pas été utilisé à cet effet.

La raison en est que IndexedDB fonctionne de manière asynchrone et ne bloque pas le fil JavaScript principal, alors que localStorage s’exécute de manière synchrone et peut bloquer le thread principal JavaScript s’il est utilisé.

Voici comment vous pouvez stocker l’image dans IndexedDB:

async function storeImages(file) {
  // Open the IndexedDB database.
  const db = await openDatabase();
  // Create a transaction with read and write access.
  const transaction = db.transaction("images", "readwrite");
  // Access the "images" object store.
  const store = transaction.objectStore("images");
  // Define the image record to be stored.
  const imageRecord = {
    id: IMAGE_ID,   // a unique ID
    image: file     // Store the image file (Blob)
  };
  // Add the image record to the store.
  const addRequest = store.add(imageRecord);
  // Handle successful addition.
  addRequest.onsuccess = () => console.log("Image added successfully!");
  // Handle errors during insertion.
  addRequest.onerror = (e) => console.error("Error storing image:", e.target.error);
}

Avec les images stockées et le jeu de synchronisation d’arrière-plan, le système est prêt à télécharger l’image chaque fois que la connexion réseau est restaurée.

Récupération et téléchargement des images

Une fois la connexion réseau restaurée, l’événement de synchronisation se déclenche et le travailleur des services récupérera l’image à partir de IndexedDB et téléchargez-le.

async function retrieveAndUploadImage(IMAGE_ID) {
  try {
    const db = await openDatabase(); // Ensure the database is open
    const transaction = db.transaction("images", "readonly");
    const store = transaction.objectStore("images");
    const request = store.get(IMAGE_ID);
    request.onsuccess = function (event) {
      const image = event.target.result;
      if (image) {
        // upload Image to server here
      } else {
        console.log("No image found with ID:", IMAGE_ID);
      }
    };
    request.onerror = () => {
        console.error("Error retrieving image.");
    };
  } catch (error) {
    console.error("Failed to open database:", error);
  }
}

Suppression de la base de données indexée

Une fois l’image téléchargée, le IndexedDB Le magasin n’est plus nécessaire. Par conséquent, il doit être supprimé avec son contenu pour libérer le stockage.

function deleteDatabase() {
  // Check if there's an open connection to the database.
  if (database) {
    database.close(); // Close the database connection
    console.log("Database connection closed.");
  }

  // Request to delete the database named "myDatabase".
  const deleteRequest = indexedDB.deleteDatabase("myDatabase");

  // Handle successful deletion of the database.
  deleteRequest.onsuccess = function () {
    console.log("Database deleted successfully!");
  };

  // Handle errors that occur during the deletion process.
  deleteRequest.onerror = function (event) {
    console.error("Error deleting database:", event.target.error);
  };

  // Handle cases where the deletion is blocked (e.g., if there are still open connections).
  deleteRequest.onblocked = function () {
    console.warn("Database deletion blocked. Close open connections and try again.");
  };
}

Avec cela, l’ensemble du processus est terminé!

Considérations et limitations

Bien que nous ayons fait beaucoup pour aider à améliorer l’expérience en prenant en charge les téléchargements hors ligne, le système n’est pas sans ses limites. J’ai pensé que je les appellerais spécifiquement parce que cela vaut la peine de savoir où cette solution pourrait ne pas répondre à vos besoins.

  • Aucune détection fiable de la connectivité Internet
    JavaScript ne fournit pas de moyen infaillible de détecter le statut en ligne. Pour cette raison, vous devez proposer une solution personnalisée pour détecter le statut en ligne.
  • Solution de chrome
    L’API de synchronisation d’arrière-plan est actuellement Limité aux navigateurs à base de chrome. En tant que tel, cette solution n’est soutenue que par des navigateurs de chrome. Cela signifie que vous aurez besoin d’une solution plus robuste si vous avez la majorité de vos utilisateurs sur des navigateurs non chromiums.
  • IndexedDB Politiques de stockage
    Les navigateurs imposent des limitations de stockage et des politiques d’expulsion pour IndexedDB. Par exemple, dans Safari, les données stockées dans IndexedDB a une durée de vie de sept jours si l’utilisateur n’interagit pas avec le site Web. C’est quelque chose que vous devez garder à l’esprit si vous trouvez une alternative pour l’API de synchronisation de fond qui prend en charge Safari.

Améliorer l’expérience utilisateur

Étant donné que l’ensemble du processus se produit en arrière-plan, nous avons besoin d’un moyen d’informer les utilisateurs lorsque les images sont stockées, en attendant d’être téléchargées ou ont été téléchargées avec succès. Implémentation de certains Éléments d’interface utilisateur À cette fin, améliorera en effet l’expérience des utilisateurs. Ces éléments d’interface utilisateur peuvent inclure des notifications de toast, des indicateurs d’état de téléchargement comme les filateurs (pour afficher des processus actifs), des barres de progression (pour afficher les progrès de l’état), des indicateurs d’état du réseau ou des boutons pour fournir des options de réessayer et d’annuler.

Emballage

Une mauvaise connectivité Internet peut perturber l’expérience utilisateur d’une application Web. Cependant, en tirant parti des technologies PWA telles que IndexedDBles travailleurs des services et l’API de synchronisation de fond, les développeurs peuvent aider à améliorer la fiabilité des applications Web pour leurs utilisateurs, en particulier celles des domaines ayant une connectivité Internet peu fiable.

Smashing Editorial
(GG, YK)




Source link