Firebase-godkendelse og apps med realtidsdatabase · Lektion

Atomare tællere og køer

Byg pålidelige atomare tællere, og implementer meddelelseskøer ved hjælp af Realtime Database til robust applikationslogik.

Lektion 3 af 412 trin

Atomare tællere og køer er en gratis Firebase-godkendelse og apps med realtidsdatabase-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Firebase-godkendelse og apps med realtidsdatabase, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Firebase-godkendelse og apps med realtidsdatabase-kurset indeholder 4 lektioner i alt.

Hvorfor atomiske handlinger er vigtige

I realtidsapplikationer kan flere brugere forsøge at opdatere de samme data samtidigt. Det kan føre til det, der kaldes en kapløbstilstand.

  • Forestil dig, at to brugere synes godt om et opslag præcis samtidig.
  • Uden korrekt håndtering kan det ene »Synes godt om« overskrive det andet.
  • Det giver forkerte data, så et opslag for eksempel viser 10 synes godt om, selv om det burde have 11.

Atomiske handlinger sikrer, at dataopdateringer udføres som én samlet, udelelig enhed, så sådanne problemer undgås.

Forståelse af atomiske tællere

En atomisk tæller er en numerisk værdi, der pålideligt kan forøges eller formindskes, selv når flere klienter forsøger at ændre den samtidigt.

Det er afgørende for funktioner som:

  • Optælling af »synes godt om« eller opstemmer til indhold.
  • Sporing af sidevisninger eller downloads.
  • Styring af lagerbeholdning i en e-handelsapp.

Firebase Realtime Database tilbyder en effektiv mekanisme til at implementere dette sikkert.

Implementering med transaktioner

Firebases metode transaction() er afgørende for at oprette atomiske handlinger. Den sikrer, at en opdateringsfunktion udføres på de nyeste data, selv når andre skrivninger sker samtidigt.

  • Din opdateringsfunktion modtager de aktuelle data.
  • Den returnerer den nye værdi, du vil skrive.
  • Firebase prøver automatisk transaktionen igen, hvis dataene ændres under processen.

Det garanterer, at dine tælleropdateringer altid er baseret på den nyeste tilstand.

Kode: Simpel atomisk tæller

Sådan forøger du en tæller atomisk ved hjælp af en transaktion. Dette eksempel simulerer Firebase-transaktionslogikken.

class MockRef {
  constructor(value) {
    this.value = value;
  }
  async transaction(updateFunction) {
    const currentValue = this.value;
    const newValue = updateFunction(currentValue);
    if (newValue !== undefined) {
      this.value = newValue;
      console.log(`Counter updated to: ${this.value}`);
      return { committed: true, snapshot: { val: () => this.value } };
    }
    return { committed: false };
  }
  val() { return this.value; }
}

async function main() {
  const counterRef = new MockRef(0);
  console.log("Initial count:", counterRef.val());

  // Attempt to increment the counter
  await counterRef.transaction(currentCount => {
    return (currentCount || 0) + 1;
  });

  console.log("Final count (after one increment):");
  console.log(counterRef.val());
}

main();

Forklaring af transaktionslogikken

I metoden transaction() modtager tilbagekaldsfunktionen currentCount. Hvis tælleren ikke findes (null), sættes den som standard til 0, før den forøges.

  • Hvis du returnerer undefined fra tilbagekaldet, afbrydes transaktionen.
  • Hvis du returnerer en anden værdi (for eksempel den forøgede tælling), gennemføres transaktionen.
  • Firebase håndterer automatisk nye forsøg, hvis dataene ændres, mens transaktionen kører.

Det sikrer, at den endelige tælling altid er korrekt, selv under stor belastning.

Introduktion til beskedkøer

En meddelelseskø er en måde, hvorpå forskellige dele af en applikation (eller forskellige applikationer) kan kommunikere asynkront. Det er som en opgaveliste til opgaver, der ikke kræver øjeblikkelig behandling.

De vigtigste fordele omfatter:

  • Afkobling: Afsendere behøver ikke vente på modtagere.
  • Pålidelighed: Opgaver gemmes, indtil de er behandlet.
  • Skalerbarhed: Du kan nemt tilføje flere arbejdere til at behandle opgaver.

Firebase Realtime Database kan fungere som en enkel og effektiv meddelelseskø.

Opbygning af en simpel kø

Hvis du vil opbygge en kø med Realtime Database, opretter du typisk en liste over opgaver. Nye opgaver føjes til denne liste, og arbejdsprocesser henter dem.

  • Hver opgave er et objekt med relevante data (f.eks. action og payload).
  • Med push() oprettes entydige nøgler, der er ordnet efter tid, hvilket er perfekt til en kø.
  • Arbejdere lytter efter nye elementer og behandler de ældste først.

Denne struktur giver robust håndtering af baggrundsopgaver.

Kode: Tilføjelse til en kø

Det er enkelt at føje opgaver til en kø ved hjælp af Firebases push()-metode. Hvert nyt element får en entydig nøgle.

class MockDatabase {
  constructor() {
    this.data = {};
  }
  ref(path) {
    return {
      push: (value) => {
        const key = `item_${Object.keys(this.data[path] || {}).length}_${Date.now()}`;
        if (!this.data[path]) {
          this.data[path] = {};
        }
        this.data[path][key] = value;
        console.log(`Added to ${path}: ${JSON.stringify(value)}`);
        return { key: key };
      },
      val: () => this.data[path]
    };
  }
}

async function main() {
  const mockDb = new MockDatabase();
  const queueRef = mockDb.ref("tasks");

  console.log("Adding tasks to the queue...");
  await queueRef.push({ action: "sendEmail", userId: "user123" });
  await queueRef.push({ action: "generateReport", reportId: "rpt456" });

  console.log("\nCurrent queue items:");
  console.log(JSON.stringify(queueRef.val(), null, 2));
}

main();

Kode: Behandling fra en kø

For at behandle opgaver pålideligt skal du sikre, at kun én arbejder behandler en given opgave. Det indebærer, at du henter den ældste opgave og derefter fjerner den atomisk eller markerer den som 'behandlet' ved hjælp af en transaktion.

class MockDatabase {
  constructor(initialData = {}) {
    this.data = initialData;
  }
  ref(path) {
    const self = this;
    return {
      orderByChild: (child) => ({ limitToFirst: (count) => ({ once: async (eventType) => {
        if (eventType === 'value') {
          const items = Object.entries(self.data[path] || {})
            .map(([key, value]) => ({ key, value }))
            .sort((a, b) => (a.value[child] || 0) - (b.value[child] || 0));
          const result = {};
          items.slice(0, count).forEach(item => { result[item.key] = item.value; });
          return { val: () => result };
        }
      }}) }),
      child: (key) => ({ transaction: async (updateFunction) => {
        const currentValue = self.data[path] ? self.data[path][key] : null;
        const newValue = updateFunction(currentValue);
        if (newValue === null) {
          delete self.data[path][key];
          console.log(`Transaction removed item: ${key}`);
          return { committed: true, snapshot: { val: () => null } };
        } else if (newValue !== undefined) {
          if (!self.data[path]) self.data[path] = {};
          self.data[path][key] = newValue;
          console.log(`Transaction updated item: ${key}`);
          return { committed: true, snapshot: { val: () => newValue } };
        }
        return { committed: false, snapshot: { val: () => currentValue } };
      }}),
      val: () => self.data[path]
    };
  }
}

async function main() {
  const initialTasks = {
    "task_A": { action: "sendEmail", userId: "user123", timestamp: 1678888000000 },
    "task_B": { action: "generateReport", reportId: "rpt456", timestamp: 1678888010000 }
  };
  const mockDb = new MockDatabase({ tasks: initialTasks });
  const queueRef = mockDb.ref("tasks");

  console.log("Initial queue items:", JSON.stringify(queueRef.val(), null, 2));

  const snapshot = await queueRef.orderByChild('timestamp').limitToFirst(1).once('value');
  const firstItem = snapshot.val();

  if (firstItem) {
    const firstKey = Object.keys(firstItem)[0];
    console.log(`Attempting to process task with key ${firstKey}`);
    const transactionResult = await queueRef.child(firstKey).transaction(currentData => {
      return currentData ? null : undefined; // Delete if exists, abort if not
    });

    if (transactionResult.committed) {
      console.log(`Successfully processed and removed task: ${firstKey}`);
    } else {
      console.log("Failed to process task (already processed or aborted).");
    }
  }
  console.log("\nQueue items after processing:");
  console.log(JSON.stringify(queueRef.val(), null, 2));
}

main();

Valg mellem tællere og køer

Selvom både atomiske tællere og køer bruger Firebase-transaktioner, løser de forskellige problemer:

  • Atomiske tællere: Til enkle numeriske opdateringer, der skal være meget konsistente (f.eks. stemmetal og lagerbeholdning).
  • Meddelelseskøer: Til afkobling af opgaver, håndtering af baggrundsprocesser og sikring af pålidelig udførelse af job, der kan behandles senere.

Når du forstår disse mønstre, kan du opbygge mere robuste og skalerbare realtidsapplikationer.

Hurtigt tjek: Atomiske operationer

Du vil pålideligt forhøje en brugers 'score' i dit spil og sikre, at samtidige opdateringer fra forskellige enheder ikke medfører mistede forhøjelser. Hvilken funktion i Firebase Realtime Database er mest passende?

Opsummering: Atomiske tællere og køer

Vi har undersøgt, hvordan Firebase Realtime Database muliggør robust applikationslogik gennem atomiske operationer.

  • Atomiske tællere bruger transaction() til pålideligt at forhøje eller formindske numeriske værdier og forhindre kapløbsbetingelser.
  • Meddelelseskøer bruger push() til at tilføje opgaver og transaction() til atomisk at behandle (reservere eller fjerne) de ældste opgaver, hvilket muliggør asynkron og skalerbar behandling i baggrunden.

Det er afgørende at mestre disse mønstre for at opbygge realtidsapplikationer med høj ydeevne, konsistens og skalerbarhed.

Gratis at komme i gang

Lær Firebase-godkendelse og apps med realtidsdatabase med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
11
Lektioner
44

Ofte stillede spørgsmål

Er lektionen “Atomare tællere og køer” gratis?

Ja — alle 3 lektioner i læringssporet Firebase-godkendelse og apps med realtidsdatabase, inklusive “Atomare tællere og køer”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Firebase-godkendelse og apps med realtidsdatabase-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Atomare tællere og køer”?

Byg pålidelige atomare tællere, og implementer meddelelseskøer ved hjælp af Realtime Database til robust applikationslogik. Du øver dig i Firebase-godkendelse og apps med realtidsdatabase med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Firebase-godkendelse og apps med realtidsdatabase?

Der kræves ingen tidligere erfaring. Firebase-godkendelse og apps med realtidsdatabase på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Atomare tællere og køer”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Firebase-godkendelse og apps med realtidsdatabase-lektion?

Ja. Alle Firebase-godkendelse og apps med realtidsdatabase-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Fan-out-opdateringer af data
  2. Transaktionelle dataoperationer
  3. Atomare tællere og køer
  4. Strategier for denormalisering og datadublering
← Tilbage til Firebase-godkendelse og apps med realtidsdatabase