Sestavte základní webovou aplikaci pomocí IndexedDB

IndexedDB je databáze NoSQL, kterou můžete použít v každém hlavním prohlížeči k ukládání spousty dat a dotazování jako v databázi, jako je MongoDB. Pokud vytváříte webovou aplikaci nebo rozšíření prohlížeče, které ukládá velké množství dat, a chcete mnoho způsobů, jak tato data dotazovat, IndexedDB je to pravé!

V tomto tutoriálu vytvoříme jednoduchou webovou aplikaci s poznámkou bez rámců jako přehled pojmů, které byste měli znát při práci s IndexedDB. Pro podrobnější pohled je dalším skvělým přehledem Mozilla Developer Network pomocí IndexedDB a také doporučuji https://www.freecodecamp.org/news/a-quick-but-complete-guide-to-indexeddb-25f030425501/ , který se více zaměřuje na metody API.

Kód pro tento výukový program najdete zde a část 2 tohoto výukového programu o přidání testovacího pokrytí do vašeho IDB kódu je zde.

Proč bych měl ve své webové aplikaci používat IndexedDB?

Jak jsem řekl nahoře, dva důvody, proč byste mohli zvolit IndexedDB před místním úložištěm, jsou:

  • Žádné omezení velikosti; pokud vaše aplikace pracuje se spoustou dat, více než s několika megabajty, které získáte s místním úložištěm a úložištěm relací, indexedDB vám umožní ukládat velké množství dat.
  • Strukturované úložiště; můžete ukládat objekty do úložišť objektů IndexedDB a dotazovat se na ně pomocí jejich polí.

To jsou také výhody, které můžete získat ukládáním dat na servery, takže pokud má váš projekt backend, můžete tam svá data vždy uložit. Pokud ale vytváříte webovou aplikaci jako první offline nebo bez backendu, je IndexedDB skvělou volbou pro váš stack. Například pracuji na rozšíření prohlížeče, které vytvoří graf vašich karet pro vizuální, interaktivní webovou historii. Proto jsem chtěl mít možnost ukládat spoustu karet, načítat je v chronologickém pořadí a aplikace nemá žádný webový backend, takže IndexedDB se perfektně hodí!

Vytváření naší databáze

Dobře, začněme vytvářet naši aplikaci! Chcete-li začít, vytvořte složku s názvem indexeddb-tutorial a v souboru s názvem db.js , přidejte tento kód, který vytvoří naši databázi!

let db;
let dbReq = indexedDB.open('myDatabase', 1);

dbReq.onupgradeneeded = function(event) {
  // Set the db variable to our database so we can use it!  
  db = event.target.result;

  // Create an object store named notes. Object stores
  // in databases are where data are stored.
  let notes = db.createObjectStore('notes', {autoIncrement: true});
}
dbReq.onsuccess = function(event) {
  db = event.target.result;
}

dbReq.onerror = function(event) {
  alert('error opening database ' + event.target.errorCode);
}

Chcete-li spustit JavaScript, vložte tento kód do souboru s názvem index.html a otevřete jej v prohlížeči Chrome:

<!DOCTYPE html>
<html>
  <head><title>IndexedDB note store</title></head>
  <body>
    <div id="app"><h1>Coming soon</h1></div>
    <script src="db.js"></script>
  </body>
</html>

Nyní v prohlížeči Chrome přejděte na nástroje pro vývojáře , klikněte na aplikaci a poté klikněte na IndexedDB v levé liště můžete vidět, že databáze byla vytvořena!

Chladný! Máme databázi s názvem myDatabase a je zde obchod s předměty (sbírka položek podobná tabulce SQL nebo kolekci v MongoDB) s názvem notes . Ale to vypadalo jako spousta kódu pro pouhé vytvoření databáze a úložiště. Co se tam tedy děje?

V prvních pár řádcích

let db;
let dbReq = indexedDB.open('myDatabase', 1);

Otevíráme verzi 1 databáze s názvem myDatabase, ale indexedDB.open nevrací databázi, vrací požadavek pro databázi, protože IndexedDB je asynchronní API. Kód IndexedDB běží za scénou, takže pokud uděláme něco, jako je uložení tisíců položek, zbytek vaší webové aplikace nepřestane spouštět svůj JavaScript a čeká na dokončení. Takže ve zbytku kódu nasloucháme, když pro nás bude naše databáze připravena s posluchači událostí :

dbReq.onupgradeneeded = function(event) {
  db = event.target.result;
  let notes = db.createObjectStore('notes', {autoIncrement: true});
}

myDatabase dříve neexistoval, takže se automaticky vytvoří a poté onupgradeneeded požáry událostí. Při zpětném volání po upgradu a pouze v tomto zpětném volání můžeme vytvořit úložiště objektů databáze. Nejprve tedy pomocí db = event.target.result , nastavíme proměnnou db uchovávat naši databázi. Poté vytvoříme jedno úložiště objektů s názvem notes .

dbReq.onsuccess = function(event) {
  db = event.target.result;
}

Tady, onsuccess spustí se po onupgradeneeded dokončí a také se spustí, pokud obnovíme stránku a znovu otevřeme databázi. Takže i tam spustíme db = event.target.result získat naši databázi, abychom ji mohli používat.

dbReq.onerror = function(event) {
  alert('error opening database ' + event.target.errorCode);
}

Konečně, pokud se něco pokazí na jakémkoli požadavku IndexedDB, jeho onerror událost se spustí, takže můžete chybu zpracovat, jak uznáte za vhodné. Právě uděláme alert .

Vložte nějaká data do databáze

Máme svou databázi, ale bez dat s ní mnoho nezmůžeme. Pojďme napsat funkci pro přidání lepící poznámky!

function addStickyNote(db, message) {
  // Start a database transaction and get the notes object store
  let tx = db.transaction(['notes'], 'readwrite');
  let store = tx.objectStore('notes');

  // Put the sticky note into the object store
  let note = {text: message, timestamp: Date.now()};
  store.add(note);

  // Wait for the database transaction to complete
  tx.oncomplete = function() { console.log('stored note!') }
  tx.onerror = function(event) {
    alert('error storing note ' + event.target.errorCode);
  }
}

Abychom to viděli v akci, vložme sadu tří volání naší funkce do našeho dbReq.onsuccess takže se spustí, jakmile je databáze připravena:

dbReq.onsuccess = function(event) {
  db = event.target.result;

  // Add some sticky notes
  addStickyNote(db, 'Sloths are awesome!');
  addStickyNote(db, 'Order more hibiscus tea');
  addStickyNote(db, 'And Green Sheen shampoo, the best for sloth fur algae grooming!');
}

Nyní obnovte soubor index.html ve svém prohlížeči, přejděte na Aplikace> IndexedDB ve vývojářských nástrojích znovu klikněte na úložiště objektů a podívejme se na naše data!

Nyní máme uložena některá data! A jak můžete vidět, naše poznámky v úložišti objektů poznámek jsou uloženy jako objekty JavaScriptu. Co se tedy v tom kódu dělo?

let tx = db.transaction(['notes'], 'readwrite');
let store = tx.objectStore('notes');

Nejprve zahájíme transakci v naší databázi zapsat data do našeho notes objektové úložiště a poté toto úložiště objektů načteme z transakce.

let note = {text: message, timestamp: Date.now()};
store.add(note);

Lepicí poznámku reprezentujeme jako objekt JavaScript a ukládáme ji do úložiště objektů voláním funkce store.add .

tx.oncomplete = function() { console.log('stored note!') }
tx.onerror = function(event) {
  alert('error storing note ' + event.target.errorCode);
}

Konečně, stejně jako náš požadavek na otevřenou databázi, tato transakce má posluchače událostí; nasloucháme akci uložení bankovky, ať už dokončení nebo chyby s oncomplete transakce a onerror posluchači.

Ještě něco, co stojí za zmínku o našich poznámkách, je to, že každá má číslo pro své Key to se počítá. Takže pokud byste po těchto třech uložili další poznámku, její klíč by byl 4. Kde se ta čísla vzala? V IndexedDB mají všechny objekty v úložišti objektů klíč jejich identifikaci a když jsme vytvořili úložiště objektů s řádkem:

let notes = db.createObjectStore('notes', {autoIncrement: true});

autoIncrement volba říká, že chceme, aby každý objekt v úložišti měl klíč, který se počítá. Můžete také vytvořit úložiště objektů pomocí řetězcových klíčů, pokud dává větší smysl ukládat a načítat objekty pod jedinečným názvem (například UUID může být řetězcový klíč pro úložiště objektů, nebo pokud jste měli úložiště objektů lenochodů, můžete identifikovat každého lenochoda řetězcovým kódováním tónu jejich pískání jako klíče).

Nyní přidáme toto addStickyNote fungovat do naší aktuální webové aplikace, takže uživatel může kliknutím odeslat poznámku. Potřebujeme textové pole, do kterého budeme odesílat poznámky, takže v div s id app , přidejte tyto značky:

<div id="textbox">
  <textarea id="newmessage"></textarea>
  <button onclick="submitNote()">Add note</button>
</div>

A přidejte tuto funkci do db.js, která se spustí pokaždé, když uživatel odešle poznámku:

function submitNote() {
  let message = document.getElementById('newmessage');
  addStickyNote(db, message.value);
  message.value = '';
}

Nyní se zbavte volání na addStickyNote v dbReq.onsuccess a když potom přejdeme na index.html a něco napíšeme do naší textové oblasti, po kliknutí na Odeslat uvidíme poznámky uložené v IndexedDB!

Než budeme pokračovat a ukážu vám, jak načíst data, abychom je mohli zobrazit, pojďme si oklikou promluvit o ústředním konceptu práce s IndexedDB, transakcích!

Transakce jsou králem v IndexedDB

Jak jste viděli v našem posledním příkladu, pro přístup k našemu notes object store jsme museli spustit db.transaction vytvořit transakci , což je sada jednoho nebo více požadavků do databáze. Vše v IndexedDB se děje prostřednictvím transakcí. Takže uložení nalepovacího lístku, otevření databáze a načtení vašich poznámek jsou všechny požadavky, ke kterým dochází v rámci transakcí.

Ve stejné transakci můžete mít také více než jeden požadavek, například pokud ukládáte mnoho položek do stejného úložiště objektů, všechny požadavky store.add mohou být provedeny ve stejné transakci, například:

function addManyNotes(db, messages) {
  let tx = db.transaction(['notes'], 'readwrite');
  let store = tx.objectStore('notes');

  for (let i = 0; i < messages.length; i++) {
    // All of the requests made from store.add are part of
    // the same transaction
    store.add({text: messages[i], timestamp: Date.now()});
  }

  // When all of these requests complete, the transaction's oncomplete
  // event fires
  tx.oncomplete = function() {console.log('transaction complete')};
}

Stejně jako požadavky mají onsuccess a onerror obsluhy událostí, transakce mají oncomplete , onerror a onabort obslužné rutiny událostí, které můžeme použít pro reakci na dokončení transakce, chybu nebo vrácení zpět.

Ale co přesně získáme tím, že každý požadavek vložíme do transakce? Pamatujte, že IndexedDB je asynchronní API, takže je možné, že bude probíhat mnoho požadavků současně. Řekněme, že jsme měli v obchodě s poznámkami nalepený lístek s nápisem „Lenoši jsou úžasní“ a požádali jsme o to, aby byl lístek velký a druhý o přidání vykřičníku do poznámky. Bez transakcí bychom mohli skončit v takové situaci:

Spustíme makeAllCaps a addExclamation akce a oba získají neupravenou poznámku „Lenoši jsou úžasní“. addExclamation uloží poznámku nejprve s vykřičníkem. makeAllCaps trvá déle a uloží poznámku „SLOTHS ARE AWESOME“ bez vykřičníku. makeAllCaps update zcela vymaže aktualizaci z addExclamation !

S transakcemi však získáme kontrolu souběžnosti . Pouze jedna transakce může vytvářet, upravovat nebo mazat položky v úložišti objektů najednou , takže to, co se skutečně děje v IndexedDB, vypadá spíše takto:

makeAllCaps transakce začíná jako první, ale od addExclamation používá stejné úložiště objektů jako makeAllCaps, nespustí se, dokud makeAllCaps neskončí. MakeAllCaps tedy skončí, addExclamation přečte poznámku velkými písmeny a poté projdou obě úpravy! 🎉

To také znamená, že pokud silnice byla obchodem s předměty a streetweeper a line painter běželi bez transakcí, link painter by mohl malovat předtím, než streetweeper přesunul větev, a dostanete toto:

Ale s běžícími transakcemi IndexedDB může streetweeper smetat větve ze silnice a čárový malíř může malovat čáry, takže lenoši mohou bezpečně vyrazit na kolo!

Než budeme pokračovat, je třeba vědět ještě jednu věc:transakce ve stejném úložišti objektů probíhají pouze jednou za čas, pokud přidávají, upravují nebo odstraňují data; jinými slovy jsou readwrite transakce, které jsou vytvořeny takto:

let tx = db.transaction(['notes', 'someOtherStore'], 'readwrite');

Zde provedeme transakci, která je pro čtení a zápis, a řekneme, že ovlivňuje notes a someOtherStore . Vzhledem k tomu, že jde o čtení, nelze jej spustit, dokud neproběhne jakákoli další transakce dotýkající se některého z těchto úložišť objektů.

Zatímco transakce čtení a zápisu jsou jedna po druhé, existují také readonly transakce; můžete jich mít tolik, kolik chcete mluvit současně se stejným úložištěm objektů, protože jim nemusíme bránit v tom, aby si navzájem nepletli data! Uděláte je takto:

// These transactions can all do their thing at the same time, even with
// overlapping object stores!
let tx = db.transaction(['notes', 'someOtherStore'], 'readonly');
let tx2 = db.transaction(['notes'], 'readonly');
let tx3 = db.transaction(['someOtherStore'], 'readonly');

Načítání jedné lepicí poznámky

Nyní, když víme, jak fungují transakce a jak fungují transakce pouze pro čtení, pojďme načíst lepicí poznámky z úložiště poznámek, abychom je mohli zobrazit. Pokud z naší databáze získáváme pouze jednu položku, použili bychom get úložiště objektů metoda, jako je tato:

// Set up an object store and transaction
let tx = db.transaction(['notes'], 'readonly');
let store = tx.objectStore('notes');

// Set up a request to get the sticky note with the key 1
let req = store.get(1);

// We can use the note if the request succeeds, getting it in the
// onsuccess handler
req.onsuccess = function(event) {
  let note = event.target.result;

  if (note) {
    console.log(note);
  } else {
    console.log("note 1 not found")
  }
}

// If we get an error, like that the note wasn't in the object
// store, we handle the error in the onerror handler
req.onerror = function(event) {
  alert('error getting note 1 ' + event.target.errorCode);
}

Provedeme transakci, vyžádáme si poznámku v úložišti poznámek pomocí klíče 1, abychom dostali náš požadavek, a poté buď použijeme získanou poznámku v onsuccess požadavku. handler, nebo zpracujeme chybu v onerror handler, pokud dostaneme chybu. Všimněte si, že pokud nalepovací lístek neexistuje, onsuccess stále se spouští, ale event.target.result bude undefined .

Vzor je podobný obsluze, kterou jsme měli pro otevření databáze; spustíme požadavek a pak dostaneme výsledek v onsuccess handler nebo zpracovat chybu v onerror psovod. Ale nechceme jen jednu poznámku, chceme zobrazit všechny poznámky. Potřebujeme je tedy získat všechny a k tomu používáme kurzor .

Načítání dat pomocí kurzorů a zobrazování poznámek

Načítání všech položek v úložišti objektů má tuto funky syntaxi:

function getAndDisplayNotes(db) {
  let tx = db.transaction(['notes'], 'readonly');
  let store = tx.objectStore('notes');

  // Create a cursor request to get all items in the store, which 
  // we collect in the allNotes array
  let req = store.openCursor();
  let allNotes = [];

  req.onsuccess = function(event) {
    // The result of req.onsuccess in openCursor requests is an
    // IDBCursor
    let cursor = event.target.result;

    if (cursor != null) {
      // If the cursor isn't null, we got an item. Add it to the
      // the note array and have the cursor continue!
      allNotes.push(cursor.value);
      cursor.continue();
    } else {
      // If we have a null cursor, it means we've gotten
      // all the items in the store, so display the notes we got.
      displayNotes(allNotes);
    }
  }

  req.onerror = function(event) {
    alert('error in cursor request ' + event.target.errorCode);
  }
}

Při běhu funkce zde jsou všechny kroky, které se stanou:

let tx = db.transaction(['notes'], 'readonly');
let store = tx.objectStore('notes');

Na začátku funkce vytvoříme transakci pouze pro čtení na notes sklad objektů. Pak dostaneme obchod a poté s store.openCursor() způsob, dostaneme žádost. To znamená, že opět pracujeme s výsledky požadavku s jeho onsuccess a onerror manipulátory, aby zpracovaly výsledky.

Uvnitř obslužné rutiny onsuccess je výsledkem události IDBCursor obsahující key lepicí poznámky, kterou drží kurzor, stejně jako samotná lepicí poznámka jako value kurzoru .

let cursor = event.target.result;
if (cursor != null) {
  allNotes.push(cursor.value);
  cursor.continue();
} else {

Pokud v příkazu if není kurzor null, znamená to, že máme další poznámku, takže přidáme value kurzoru do našeho pole poznámek a pokračujte v načítání poznámek voláním cursor.continue .

} else {
  displayNotes(allNotes);
}

Pokud je ale kurzor prázdný, nejsou k dispozici žádné další poznámky k načtení, takže poznámky zobrazíme tak, že je předáme na displayNotes funkce.

Hmm, tohle cursor.continue() věc vypadá jako smyčka while, ale neprobíhá žádná smyčka ani tok ovládání. Jak tedy přesně zacyklíme? Tento řádek vám dá nápovědu:

req.onsuccess = function(event) {

Ukázalo se to pokaždé, když zavoláte na číslo cursor.continue() , spustí se událost a odešle kurzor s další položkou do obslužné rutiny onsuccess. Tedy v každém onsuccess , sbíráme další poznámku, dokud nedosáhneme úspěchu, kde je kurzor nulový. Takto iterujeme naše data pomocí kurzorů.

Chcete-li nyní tyto poznámky zobrazit v souboru index.html, po prvku div textového pole, přidejte pod textové pole prvek div, do kterého budou uloženy naše rychlé poznámky:

<div id="notes"></div>

A v db.js přidejte tuto funkci pro zobrazení poznámek:

function displayNotes(notes) {
  let listHTML = '<ul>';
  for (let i = 0; i < notes.length; i++) {
    let note = notes[i];
    listHTML += '<li>' + note.text + ' ' + 
      new Date(note.timestamp).toString() + '</li>';
  }

  document.getElementById('notes').innerHTML = listHTML;
}

Tato funkce pouze převede každou notu na <li> tag a zobrazí je jako seznam pomocí starého JavaScriptu.

Nyní, když máme funkci pro zobrazení všech poznámek, přidáme ji na několik míst. Při prvním otevření aplikace budeme chtít vidět všechny naše rychlé poznámky, takže při prvním otevření databáze bychom měli zavolat na číslo getAndDisplayNotes v dbReq.onsuccess :

dbReq.onsuccess = function(event) {
  db = event.target.result;
  // Once the database is ready, display the notes we already have!
  getAndDisplayNotes(db);
}

A když přidáte poznámku, měli byste ji okamžitě vidět, takže v addStickyNote , změňme transakci po dokončení zpětného volání na volání getAndDisplayNotes :

tx.oncomplete = function() { getAndDisplayNotes(db); }

Nyní znovu otevřete stránku v Chrome a zkuste přidat další poznámky. Mělo by to vypadat nějak takhle!

A teď poslední věc, udělejme režim, který nejprve zobrazí nejnovější poznámky a zjistí, proč se tomu říká IndexedDB!

Indexy, uvedení indexovaných v IndexedDB

Máme toto úložiště poznámek a ukládáme poznámky s časovými razítky, takže by mělo dávat smysl, že bychom měli být schopni načíst všechny lepicí papírky pro určitý časový rozsah (jako všechny lepicí poznámky za posledních 10 minut) nebo mít možnost načíst je jako první s nejnovějšími, že?

Můžeme, ale abychom se mohli dotazovat podle pole časového razítka, musíme tomuto poli v úložišti objektů poznámek dát index . Jakmile máme tento index, můžeme se podle něj dotazovat. Pamatujte však, že jakékoli změny ve struktuře databáze musí proběhnout uvnitř onupgradeneeded databázového požadavku handler, takže potřebujeme zvýšit verzi naší databáze, abychom vytvořili index, takto:

// We update the version of the database to 2 to trigger
// onupgradeneeded
let dbReq = indexedDB.open('myDatabase', 2);
dbReq.onupgradeneeded = function(event) {
  db = event.target.result;

  // Create the notes object store, or retrieve that store if it
  // already exists.
  let notes;
  if (!db.objectStoreNames.contains('notes')) {
    notes = db.createObjectStore('notes', {autoIncrement: true});
  } else {
    notes = dbReq.transaction.objectStore('notes');
  }

  // If there isn't already a timestamp index in our notes object
  // store, make one so we can query notes by their timestamps
  if (!notes.indexNames.contains('timestamp')) {
    notes.createIndex('timestamp', 'timestamp');
  }
}

Nejprve aktualizujeme verzi naší databáze na 2, což znamená, že se struktura databáze mění, takže to způsobí onupgradeneeded událost vypálit.

Nyní máme upgrade verze, kde úložiště objektů poznámky již existovalo, takže zkontrolujeme, zda již existuje úložiště poznámek s db.objectStoreNames :

if (!db.objectStoreNames.contains('notes')) {

a pokud již existuje úložiště objektů, načteme jej pomocí dbReq.transaction.objectStore :

notes = dbReq.transaction.objectStore('notes');

Nakonec přidáme index s createIndex :

notes.createIndex('timestamp', 'timestamp');

První parametr je název našeho indexu a druhý je keyPath indexu . Index je ve skutečnosti sám o sobě úložištěm objektů, takže všechny položky v indexu mají klíč. Pokud tedy zadáte indexu keyPath timestamp , pak časové razítko každého objektu v úložišti objektů bude jeho klíčem.

Kromě toho existuje volitelný parametr objektu třetí možnosti. Řekněme, že naše poznámky měly názvy a chtěli jsme vyžadovat, aby nebylo možné uložit poznámku, pokud měla stejný název jako jiná poznámka. Mohli bychom to udělat vytvořením jedinečného indexu titulů, jako je tento:

notes.createIndex('title', 'title', {unique: true});

Chcete-li zobrazit náš nový index, po aktualizaci onupgradeneeded , obnovte index.html v Chromu (možná budete muset X z Chromu vidět změnu), přejděte znovu na Nástroje pro vývojáře> Aplikace> IndexedDB a měli byste vidět nový index časového razítka v úložišti objektů pro poznámky:

Jak můžete vidět, poznámky jsou nyní uvedeny podle jejich časových razítek jako jejich primární klíče. A ve skutečnosti má index jako úložiště objektů stejné get a openCursor metody, které by běžné úložiště objektů mělo. Například bychom mohli požádat o první poznámku v tomto seznamu voláním na:

tx.objectStore('notes').index('timestamp').get(1533144673015);

Dobře. Nyní, když máme skvělý nový index, přidáme do naší webové aplikace režim pro převrácení pořadí, ve kterém se poznámky zobrazují. Nejprve do db.js přidejte globální proměnnou bool:

let reverseOrder = false;

Pak v getAndDisplayNotes stačí aktualizovat náš požadavek, abychom používali náš index časových razítek a abychom si vybrali, ze kterého směru budeme číst lepicí poznámky.

let tx = db.transaction(['notes'], 'readonly');
let store = tx.objectStore('notes');

// Retrieve the sticky notes index to run our cursor query on; 
// the results will be ordered by their timestamp
let index = store.index('timestamp');

// Create our openCursor request, on the index rather than the main
// notes object store. If we're going in reverse, then specify the
// direction as "prev". Otherwise, we specify it as "next".
let req = index.openCursor(null, reverseOrder ? 'prev' : 'next');

V store.index() , načteme index s názvem, který požadujeme, stejně jako při získávání úložiště objektů z transakce. Nyní můžeme definovat požadavek na kurzor na tomto indexu, abychom získali zpět naše poznámky seřazené podle časového razítka.

index.openCursor má dva volitelné parametry. První, pokud není null, nám umožňuje zadat rozsah položek, které chceme načíst. Pokud bychom například chtěli pouze rychlé poznámky z minulé hodiny, mohli bychom otevřít kurzor takto:

let anHourAgoInMilliseconds = Date.now() - 60 * 60 * 1000;

// IDBKeyRange is a global variable for defining ranges to query
// indices on
let keyRange = IDBKeyRange.lowerBound(anHourAgoInMilliseconds);
let req = index.openCursor(keyRange, 'next');

Druhým parametrem je pořadí, ve kterém chceme položky načíst, což může být 'prev' nebo 'next' , takže svůj směr upřesníme předáním reverseOrder ? 'prev' : 'next' .

Nakonec se podívejme na to v akci; v index.html přidejte další funkci. Toto bude pro převrácení pořadí poznámek, které zobrazujeme:

function flipNoteOrder(notes) {
  reverseOrder = !reverseOrder;
  getAndDisplayNotes(db);
}

A chcete-li použít funkci flipNoteOrder z našeho uživatelského rozhraní, přidejte do index.html ještě jedno tlačítko pro převrácení pořadí poznámek.

<button onclick="flipNoteOrder()">Flip note order</button>

A pokud Chrome obnovíte, vaše přepínací tlačítko by nyní mělo fungovat!

Chladný! Nyní můžeme změnit pořadí, ve kterém vidíme poznámky! Nyní jste viděli základy IndexedDB. Existují další funkce, které jsme v akci neviděli, jako je mazání objektů, ukládání binárních dat do IndexedDB a indexy s více poli, ale toto by měl být dobrý výchozí bod pro vytváření webových aplikací s IndexedDB.

Jak jste však mohli vidět, základní API IndexedDB, i když je výkonné, ve skutečnosti nemá ergonomický pocit. Nevím jak vám, ale mně se tito posluchači na událostech zdají nepohodlné, aby se o tom uvažovalo, a tito zpracovatelé také přemýšleli, když jsem poprvé přišel na to, jak poskytnout testovací pokrytí kódu IndexedDB. Navíc, jak máme zajistit pokrytí tohoto API automatickým testováním?

V mých několika následujících tutoriálech vám ukážu, jak refaktorovat tento kód, aby byl testovatelný, a poté v dalším tutoriálu, jak jej refaktorovat, aby se s ním lépe pracovalo! Až příště,

ZŮSTAŇTE DLOUHÝ!

Část 2 tohoto tutoriálu o testovacím pokrytí pro IndexedDB

[Část 3 tohoto tutoriálu se právě připravuje]