Bekerja Dengan IndexedDB
Indonesian (Bahasa Indonesia) translation by Zadip (you can also view the original English article)
Salah satu perkembangan yang lebih menarik dalam standar web akhir-akhir ini adalah spesifikasi Indexed Database (IndexedDB for short). Untuk waktu yang menyenangkan, Anda dapat membaca sendiri spek itu. Dalam tutorial ini saya akan menjelaskan fitur ini dan semoga memberi Anda beberapa inspirasi untuk menggunakan fitur canggih ini sendiri.
Overview
Sebagai spesifikasi, IndexedDB saat ini adalah Rekomendasi Kandidat.
Singkatnya, IndexedDB menyediakan cara bagi Anda untuk menyimpan sejumlah besar data di browser pengguna Anda. Aplikasi apa pun yang perlu mengirim banyak data melalui kabel dapat sangat bermanfaat karena dapat menyimpan data tersebut pada klien. Tentu saja penyimpanan hanya bagian dari persamaan. IndexedDB juga menyediakan API pencarian berbasis indeks yang kuat untuk mengambil data yang Anda butuhkan.
Anda mungkin bertanya-tanya bagaimana IndexedDB berbeda dari mekanisme penyimpanan lainnya?
Cookie sangat didukung dengan baik, tetapi memiliki implikasi hukum dan ruang penyimpanan yang terbatas. Juga - mereka dikirim bolak-balik ke server dengan setiap permintaan, benar-benar meniadakan manfaat dari penyimpanan sisi-klien.
Penyimpanan Lokal juga didukung dengan sangat baik, tetapi terbatas dalam hal jumlah total penyimpanan yang dapat Anda gunakan. Penyimpanan Lokal tidak menyediakan API "penelusuran" yang sebenarnya karena data hanya diambil melalui nilai kunci. Penyimpanan Lokal sangat bagus untuk hal-hal "khusus" yang mungkin ingin Anda simpan, misalnya preferensi, sedangkan IndexedDB lebih sesuai untuk data Ad Hoc (seperti halnya basis data).
Sebelum kita melangkah lebih jauh, mari kita bicara jujur tentang keadaan IndexedDB dalam hal dukungan browser. Sebagai spesifikasi, IndexedDB saat ini adalah Rekomendasi Kandidat. Pada titik ini orang-orang di belakang spesifikasi senang dengan itu tetapi sekarang mencari umpan balik dari komunitas pengembang. Spesifikasi dapat berubah antara sekarang dan tahap akhir, Rekomendasi W3C. Secara umum, browser yang mendukung IndexedDB sekarang semua dilakukan dengan cara yang cukup konsisten, tetapi pengembang harus siap untuk menangani awalan dan mencatat pembaruan di masa mendatang.
Adapun browser yang mendukung IndexedDB, Anda punya sedikit dilema. Dukungan cukup sangat bagus untuk desktop, tetapi hampir tidak ada untuk ponsel. Mari kita lihat apa yang dikatakan situs hebat CanIUse.com:



Chrome untuk Android mendukung fitur ini, tetapi sangat sedikit orang yang saat ini menggunakan browser itu di perangkat Android. Apakah kurangnya dukungan seluler menyiratkan bahwa Anda tidak boleh menggunakannya? Tentu saja tidak! Semoga semua pembaca kita akrab dengan konsep peningkatan progresif. Fitur seperti IndexedDB dapat ditambahkan ke aplikasi Anda dengan cara yang tidak akan merusak browser yang tidak didukung. Anda bisa menggunakan perpustakaan wrapper untuk beralih ke WebSQL di ponsel, atau cukup lewati menyimpan data secara lokal di klien seluler Anda. Secara pribadi, saya yakin kemampuan untuk menyimpan banyak data pada klien cukup penting untuk digunakan sekarang bahkan tanpa dukungan seluler.
Mari Kita Mulai
Kita telah membahas spesifikasi dan dukungan, sekarang mari kita lihat menggunakan fitur ini. Hal pertama yang harus kita lakukan adalah memeriksa dukungan IndexedDB. Meskipun ada alat di luar sana yang menyediakan cara umum untuk memeriksa fitur peramban, kita dapat menjadikan ini jauh lebih sederhana karena kita hanya memeriksa satu hal tertentu.
1 |
document.addEventListener("DOMContentLoaded", function(){ |
2 |
|
3 |
if("indexedDB" in window) { |
4 |
console.log("YES!!! I CAN DO IT!!! WOOT!!!"); |
5 |
} else { |
6 |
console.log("I has a sad."); |
7 |
}
|
8 |
|
9 |
},false); |
Cuplikan kode di atas (tersedia di test1.html jika Anda mengunduh file zip yang dilampirkan pada artikel ini) menggunakan acara DOMContentLoaded untuk menunggu halaman dimuat. (Ok, itu agak jelas, tapi saya menyadari ini mungkin tidak akrab bagi orang-orang yang hanya menggunakan jQuery.) Saya kemudian hanya melihat apakah indexedDB ada di objek window dan jika demikian, kita baik untuk pergi. Itu adalah contoh yang paling sederhana, tetapi biasanya kita mungkin ingin menyimpan ini sehingga kita tahu nanti apakah kita dapat menggunakan fitur ini. Berikut ini contoh yang sedikit lebih maju (test2.html).
1 |
var idbSupported = false; |
2 |
|
3 |
document.addEventListener("DOMContentLoaded", function(){ |
4 |
|
5 |
if("indexedDB" in window) { |
6 |
idbSupported = true; |
7 |
}
|
8 |
|
9 |
},false); |
Semua yang saya lakukan adalah menciptakan variabel global, idbSupported, yang dapat digunakan sebagai tanda untuk melihat apakah browser saat ini dapat menggunakan IndexedDB.
Membuka Database
IndexedDB, seperti yang Anda bayangkan, memanfaatkan basis data. Untuk jelasnya, ini bukan implementasi SQL Server. Database ini bersifat lokal untuk browser dan hanya tersedia untuk pengguna. Database IndexedDB mengikuti aturan yang sama seperti cookie dan penyimpanan lokal. Database adalah unik untuk domain yang dimuat. Jadi misalnya, database bernama "Foo" yang dibuat di foo.com tidak akan bertentangan dengan database dengan nama yang sama di goo.com. Tidak hanya itu tidak konflik, itu tidak akan tersedia untuk domain lain juga. Anda dapat menyimpan data untuk situs web Anda mengetahui bahwa situs web lain tidak akan dapat mengaksesnya.
Membuka database dilakukan melalui perintah terbuka. Dalam penggunaan dasar Anda memberikan nama dan versi. Versi ini sangat penting untuk alasan saya akan membahas lebih lanjut nanti. Inilah contoh sederhana:
1 |
var openRequest = indexedDB.open("test",1); |
Membuka database adalah operasi asynchronous. Untuk menangani hasil dari operasi ini, Anda perlu menambahkan beberapa pendengar acara. Ada empat jenis peristiwa yang dapat dipicu:
- success
- error
- upgradeneeded
- blocked
Anda mungkin bisa menebak apa arti sukses dan kesalahan. Peristiwa yang ditingkatkan penggunaannya digunakan baik ketika pengguna pertama kali membuka database maupun ketika Anda mengubah versi. Diblokir bukan sesuatu yang akan terjadi biasanya, tetapi dapat diaktifkan jika koneksi sebelumnya tidak pernah ditutup.
Biasanya yang harus terjadi adalah bahwa pada klik pertama ke situs Anda, acara yang ditingkatkan versinya akan diaktifkan. Setelah itu - hanya handler yang sukses. Mari kita lihat contoh sederhana (test3.html).
1 |
var idbSupported = false; |
2 |
var db; |
3 |
|
4 |
document.addEventListener("DOMContentLoaded", function(){ |
5 |
|
6 |
if("indexedDB" in window) { |
7 |
idbSupported = true; |
8 |
}
|
9 |
|
10 |
if(idbSupported) { |
11 |
var openRequest = indexedDB.open("test",1); |
12 |
|
13 |
openRequest.onupgradeneeded = function(e) { |
14 |
console.log("Upgrading..."); |
15 |
}
|
16 |
|
17 |
openRequest.onsuccess = function(e) { |
18 |
console.log("Success!"); |
19 |
db = e.target.result; |
20 |
}
|
21 |
|
22 |
openRequest.onerror = function(e) { |
23 |
console.log("Error"); |
24 |
console.dir(e); |
25 |
}
|
26 |
|
27 |
}
|
28 |
|
29 |
},false); |
Sekali lagi kita memeriksa untuk melihat apakah IndexedDB benar-benar didukung, dan jika ya, kita membuka database. Kita telah membahas tiga acara di sini - pembaruan yang diperlukan acara, acara sukses, dan peristiwa kesalahan. Untuk sekarang fokus pada acara sukses. Acara ini dilewatkan pawang melalui target.result. Kita telah menyalinnya ke variabel global yang disebut db. Ini adalah sesuatu yang akan kita gunakan nanti untuk benar-benar menambahkan data. Jika Anda menjalankan ini di browser Anda (dalam satu yang mendukung IndexedDB tentu saja!), Anda akan melihat pesan peningkatan dan keberhasilan di konsol Anda saat pertama kali Anda menjalankan skrip. Yang kedua, dan seterusnya, saat Anda menjalankan skrip, Anda seharusnya hanya melihat pesan sukses.
Toko Obyek
Sejauh ini kita sudah memeriksa dukungan IndexedDB, menegaskannya, dan membuka koneksi ke database. Sekarang kita membutuhkan tempat untuk menyimpan data. IndexedDB memiliki konsep "Toko Obyek." Anda dapat menganggap ini sebagai tabel database tipikal. (Ini jauh lebih longgar daripada tabel database yang khas, tapi jangan khawatir tentang itu sekarang.) Toko-toko objek memiliki data (jelas) tetapi juga keypath dan set opsional indeks. Keypath pada dasarnya merupakan pengenal unik untuk data Anda dan memiliki beberapa format berbeda. Indeks akan dibahas nanti ketika kita mulai berbicara tentang mengambil data.
Sekarang untuk sesuatu yang krusial. Ingat acara yang ditingkatkan yang disebutkan sebelumnya? Anda hanya dapat membuat toko objek selama acara yang ditingkatkan. Sekarang - secara default - ini akan berjalan secara otomatis saat pertama kali pengguna mengunjungi situs Anda. Anda dapat menggunakan ini untuk membuat toko objek Anda. Hal penting untuk diingat adalah bahwa jika Anda perlu memodifikasi toko objek Anda, Anda akan perlu meng-upgrade versi (kembali ke acara terbuka tersebut) dan menulis kode untuk menangani perubahan Anda. Mari kita lihat contoh sederhana dari aksi ini.
1 |
var idbSupported = false; |
2 |
var db; |
3 |
|
4 |
document.addEventListener("DOMContentLoaded", function(){ |
5 |
|
6 |
if("indexedDB" in window) { |
7 |
idbSupported = true; |
8 |
}
|
9 |
|
10 |
if(idbSupported) { |
11 |
var openRequest = indexedDB.open("test_v2",1); |
12 |
|
13 |
openRequest.onupgradeneeded = function(e) { |
14 |
console.log("running onupgradeneeded"); |
15 |
var thisDB = e.target.result; |
16 |
|
17 |
if(!thisDB.objectStoreNames.contains("firstOS")) { |
18 |
thisDB.createObjectStore("firstOS"); |
19 |
}
|
20 |
|
21 |
}
|
22 |
|
23 |
openRequest.onsuccess = function(e) { |
24 |
console.log("Success!"); |
25 |
db = e.target.result; |
26 |
}
|
27 |
|
28 |
openRequest.onerror = function(e) { |
29 |
console.log("Error"); |
30 |
console.dir(e); |
31 |
}
|
32 |
|
33 |
}
|
34 |
|
35 |
},false); |
Contoh ini (test4.html) dibangun di atas entri sebelumnya jadi saya akan fokus pada apa yang baru. Dalam acara yang ditingkatkan, saya telah menggunakan variabel database yang dilewatkan ke sana (thisDB). Salah satu sifat dari variabel ini adalah daftar toko objek yang ada yang disebut objectStoreNames. Bagi orang yang ingin tahu, ini bukan array sederhana tetapi "DOMStringList." Jangan tanya saya - tapi ini dia. Kita dapat menggunakan metode berisi untuk melihat apakah toko objek kita ada, dan jika tidak, buatlah. Ini adalah salah satu dari beberapa fungsi sinkron di IndexedDB sehingga kita tidak perlu mendengarkan hasilnya.
Untuk meringkas kemudian - ini adalah apa yang akan terjadi ketika seorang pengguna mengunjungi situs Anda. Pertama kali mereka ada di sini, acara yang ditingkatkan kualitasnya menyala. Kode memeriksa untuk melihat apakah toko objek, "firstOS" ada. Tidak akan. Oleh karena itu - itu dibuat. Kemudian handler sukses berjalan. Kali kedua mereka mengunjungi situs, nomor versi akan sama sehingga acara yang ditingkatkan kualitasnya tidak diaktifkan.
Sekarang bayangkan Anda ingin menambahkan toko objek kedua. Yang perlu Anda lakukan hanyalah menaikkan nomor versi dan pada dasarnya menduplikasi blok kode contains/createObjectStore yang Anda lihat di atas. Yang keren adalah bahwa kode yang Anda perbarui akan mendukung baik orang-orang yang baru ke situs maupun mereka yang sudah memiliki toko objek pertama. Berikut ini contohnya (test5.html):
1 |
var openRequest = indexedDB.open("test_v2",2); |
2 |
|
3 |
openRequest.onupgradeneeded = function(e) { |
4 |
console.log("running onupgradeneeded"); |
5 |
var thisDB = e.target.result; |
6 |
|
7 |
if(!thisDB.objectStoreNames.contains("firstOS")) { |
8 |
thisDB.createObjectStore("firstOS"); |
9 |
}
|
10 |
|
11 |
if(!thisDB.objectStoreNames.contains("secondOS")) { |
12 |
thisDB.createObjectStore("secondOS"); |
13 |
}
|
14 |
|
15 |
}
|
Menambahkan Data
Setelah Anda memiliki toko objek Anda siap, Anda dapat mulai menambahkan data. Ini - mungkin - salah satu aspek terkeren dari IndexedDB. Tidak seperti database berbasis tabel tradisional, IndexedDB memungkinkan Anda menyimpan objek apa adanya. Apa itu artinya Anda dapat mengambil objek JavaScript generik dan simpan saja. Selesai Tentunya ada beberapa peringatan di sini, tetapi untuk sebagian besar, itu saja.
Bekerja dengan data mengharuskan Anda untuk menggunakan transaksi. Transaksi mengambil dua argumen. Yang pertama adalah array tabel yang akan Anda kerjakan. Sebagian besar waktu ini akan menjadi satu meja. Argumen kedua adalah jenis transaksi. Ada dua jenis transaksi: readonly dan readwrite. Menambahkan data akan menjadi operasi baca-tulis. Mari kita mulai dengan membuat transaksi:
1 |
//Assume db is a database variable opened earlier
|
2 |
var transaction = db.transaction(["people"],"readwrite"); |
Perhatikan toko objek, "orang", hanyalah salah satu yang kita buat dalam contoh di atas. Demo lengkap kita berikutnya akan memanfaatkannya. Setelah mendapatkan transaksi, Anda kemudian meminta toko objek yang Anda katakan akan bekerja dengan:
1 |
var store = transaction.objectStore("people"); |
Sekarang Anda punya toko Anda dapat menambahkan data. Ini dilakukan melalui - tunggu untuk itu - add metode.
1 |
//Define a person
|
2 |
var person = { |
3 |
name:name, |
4 |
email:email, |
5 |
created:new Date() |
6 |
}
|
7 |
|
8 |
//Perform the add
|
9 |
var request = store.add(person,1); |
Ingat sebelumnya kita mengatakan bahwa Anda dapat menyimpan data apa pun yang Anda inginkan (untuk sebagian besar). Jadi objek orang saya di atas benar-benar sewenang-wenang. Saya bisa menggunakan firstName dan lastName, bukan hanya nama. Saya bisa menggunakan properti gender. Anda mendapatkan ide itu. Argumen kedua adalah kunci yang digunakan untuk mengidentifikasi data secara unik. Dalam hal ini kita telah mengkodekannya dengan keras ke 1 yang akan menyebabkan masalah cukup cepat. Tidak apa-apa - kita akan belajar cara memperbaikinya.
Operasi penambahan tidak sinkron, jadi mari tambahkan dua penangan kejadian untuk hasilnya.
1 |
request.onerror = function(e) { |
2 |
console.log("Error",e.target.error.name); |
3 |
//some type of error handler
|
4 |
}
|
5 |
|
6 |
request.onsuccess = function(e) { |
7 |
console.log("Woot! Did it"); |
8 |
}
|
Kita memiliki penangan onerror untuk kesalahan dan onsuccess untuk perubahan yang baik. Cukup jelas, tetapi mari kita lihat contoh lengkapnya. Anda dapat menemukannya di file test6.html.
1 |
<!doctype html>
|
2 |
<html>
|
3 |
<head>
|
4 |
</head>
|
5 |
|
6 |
<body>
|
7 |
|
8 |
<script>
|
9 |
var db; |
10 |
|
11 |
function indexedDBOk() { |
12 |
return "indexedDB" in window; |
13 |
}
|
14 |
|
15 |
document.addEventListener("DOMContentLoaded", function() { |
16 |
|
17 |
//No support? Go in the corner and pout.
|
18 |
if(!indexedDBOk) return; |
19 |
|
20 |
var openRequest = indexedDB.open("idarticle_people",1); |
21 |
|
22 |
openRequest.onupgradeneeded = function(e) { |
23 |
var thisDB = e.target.result; |
24 |
|
25 |
if(!thisDB.objectStoreNames.contains("people")) { |
26 |
thisDB.createObjectStore("people"); |
27 |
}
|
28 |
}
|
29 |
|
30 |
openRequest.onsuccess = function(e) { |
31 |
console.log("running onsuccess"); |
32 |
|
33 |
db = e.target.result; |
34 |
|
35 |
//Listen for add clicks
|
36 |
document.querySelector("#addButton").addEventListener("click", addPerson, false); |
37 |
}
|
38 |
|
39 |
openRequest.onerror = function(e) { |
40 |
//Do something for the error
|
41 |
}
|
42 |
|
43 |
},false); |
44 |
|
45 |
function addPerson(e) { |
46 |
var name = document.querySelector("#name").value; |
47 |
var email = document.querySelector("#email").value; |
48 |
|
49 |
console.log("About to add "+name+"/"+email); |
50 |
|
51 |
var transaction = db.transaction(["people"],"readwrite"); |
52 |
var store = transaction.objectStore("people"); |
53 |
|
54 |
//Define a person
|
55 |
var person = { |
56 |
name:name, |
57 |
email:email, |
58 |
created:new Date() |
59 |
}
|
60 |
|
61 |
//Perform the add
|
62 |
var request = store.add(person,1); |
63 |
|
64 |
request.onerror = function(e) { |
65 |
console.log("Error",e.target.error.name); |
66 |
//some type of error handler
|
67 |
}
|
68 |
|
69 |
request.onsuccess = function(e) { |
70 |
console.log("Woot! Did it"); |
71 |
}
|
72 |
}
|
73 |
</script>
|
74 |
|
75 |
<input type="text" id="name" placeholder="Name"><br/> |
76 |
<input type="email" id="email" placeholder="Email"><br/> |
77 |
<button id="addButton">Add Data</button> |
78 |
|
79 |
</body>
|
80 |
</html>
|
Contoh di atas berisi formulir kecil dengan tombol untuk mengaktifkan acara untuk menyimpan data dalam IndexedDB. Jalankan ini di browser Anda, tambahkan sesuatu ke bidang formulir, dan klik tambahkan. Jika Anda membuka alat dev browser Anda, Anda akan melihat sesuatu seperti ini.



Ini adalah waktu yang tepat untuk menunjukkan bahwa Chrome memiliki penampil yang sangat baik untuk data IndexedDB. Jika Anda mengklik pada tab Sumber Daya, memperluas bagian IndexedDB, Anda dapat melihat database yang dibuat oleh demo ini serta objek yang baru saja dimasukkan.



Untuk itu, lanjutkan dan tekan tombol Add Data itu lagi. Anda akan melihat kesalahan di konsol:



Pesan kesalahan harus menjadi petunjuk. ConstraintError berarti kita hanya mencoba menambahkan data dengan kunci yang sama dengan yang sudah ada. Jika Anda ingat, kita keras kode kunci itu dan kita tahu itu akan menjadi masalah. Saatnya bicara kunci.
Kunci
Kunci adalah kunci utama versi IndexedDB. Database tradisional dapat memiliki tabel tanpa kunci, tetapi setiap toko objek harus memiliki kunci. IndexedDB memungkinkan untuk beberapa jenis kunci yang berbeda.
Opsi pertama adalah hanya menentukan sendiri, seperti yang kita lakukan di atas. Kita bisa menggunakan logika untuk menghasilkan kunci unik.
Pilihan kedua Anda adalah keypath, di mana kunci didasarkan pada properti dari data itu sendiri. Pertimbangkan contoh orang-orang kita - kita dapat menggunakan alamat email sebagai kunci.
Pilihan ketiga Anda, dan menurut saya, yang paling sederhana, adalah menggunakan generator kunci. Ini berfungsi seperti kunci primer yang bersifat otomatis dan merupakan metode paling sederhana untuk menentukan kunci.
Kunci ditentukan ketika toko objek dibuat. Berikut dua contoh - satu menggunakan jalur kunci dan satu generator.
1 |
thisDb.createObjectStore("test", { keyPath: "email" }); |
2 |
thisDb.createObjectStore("test2", { autoIncrement: true }); |
Kita dapat memodifikasi demo kita sebelumnya dengan membuat toko objek dengan kunci autoIncrement:
1 |
thisDB.createObjectStore("people", {autoIncrement:true}); |
Akhirnya, kita dapat mengambil Add call yang kita gunakan sebelumnya dan menghapus kunci kode keras:
1 |
var request = store.add(person); |
Itu dia! Sekarang Anda dapat menambahkan data sepanjang hari. Anda dapat menemukan versi ini di test7.html.
Membaca Data
Sekarang mari beralih untuk membaca setiap bagian data (kita akan membahas membaca set data yang lebih besar nanti). Sekali lagi, ini akan dilakukan dalam suatu transaksi dan akan menjadi tidak sinkron. Inilah contoh sederhana:
1 |
var transaction = db.transaction(["test"], "readonly"); |
2 |
var objectStore = transaction.objectStore("test"); |
3 |
|
4 |
//x is some value
|
5 |
var ob = objectStore.get(x); |
6 |
|
7 |
ob.onsuccess = function(e) { |
8 |
|
9 |
}
|
Perhatikan bahwa transaksi hanya bisa dibaca. Panggilan API hanya panggilan get sederhana dengan kunci yang dilewati. Sebagai cepat samping, jika Anda berpikir menggunakan IndexedDB adalah sedikit verbose, perhatikan Anda dapat rantai banyak dari panggilan tersebut juga. Inilah kode yang persis sama yang ditulis lebih ketat:
1 |
db.transaction(["test"], "readonly").objectStore("test").get(X).onsuccess = function(e) {} |
Secara pribadi saya masih menemukan IndexedDB agak kompleks jadi saya lebih suka pendekatan 'pecah' untuk membantu saya melacak apa yang sedang terjadi.
Hasil dari handler onget get adalah objek yang Anda simpan sebelumnya. Setelah Anda memiliki objek itu, Anda dapat melakukan apa pun yang Anda inginkan. Di demo kita berikutnya (test8.html) Kita telah menambahkan kolom formulir sederhana untuk membiarkan Anda memasukkan kunci dan mencetak hasilnya. Berikut ini contohnya:



Handler untuk tombol Dapatkan Data ada di bawah:
1 |
function getPerson(e) { |
2 |
var key = document.querySelector("#key").value; |
3 |
if(key === "" || isNaN(key)) return; |
4 |
|
5 |
var transaction = db.transaction(["people"],"readonly"); |
6 |
var store = transaction.objectStore("people"); |
7 |
|
8 |
var request = store.get(Number(key)); |
9 |
|
10 |
request.onsuccess = function(e) { |
11 |
|
12 |
var result = e.target.result; |
13 |
console.dir(result); |
14 |
if(result) { |
15 |
var s = "<h2>Key "+key+"</h2><p>"; |
16 |
for(var field in result) { |
17 |
s+= field+"="+result[field]+"<br/>"; |
18 |
}
|
19 |
document.querySelector("#status").innerHTML = s; |
20 |
} else { |
21 |
document.querySelector("#status").innerHTML = "<h2>No match</h2>"; |
22 |
}
|
23 |
}
|
24 |
}
|
Untuk sebagian besar, ini harus jelas. Dapatkan nilai dari lapangan dan jalankan panggilan dapatkan di toko objek yang diperoleh dari transaksi. Perhatikan bahwa kode tampilan hanya mendapatkan semua bidang dan membuangnya. Dalam aplikasi nyata, Anda akan (mudah-mudahan) tahu apa isi data Anda dan bekerja dengan bidang tertentu.
Membaca Lebih Banyak Data
Jadi itulah bagaimana Anda akan mendapatkan satu bagian data. Bagaimana dengan banyak data? IndexedDB memiliki dukungan untuk apa yang disebut kursor. Kursor memungkinkan Anda melakukan iterasi terhadap data. Anda dapat membuat kursor dengan rentang opsional (filter dasar) dan arah.
Sebagai contoh, blok kode berikut membuka kursor untuk mengambil semua data dari toko objek. Seperti semua hal lain yang telah kita lakukan dengan data ini adalah asynchronous dan dalam suatu transaksi.
1 |
var transaction = db.transaction(["test"], "readonly"); |
2 |
var objectStore = transaction.objectStore("test"); |
3 |
|
4 |
var cursor = objectStore.openCursor(); |
5 |
|
6 |
cursor.onsuccess = function(e) { |
7 |
var res = e.target.result; |
8 |
if(res) { |
9 |
console.log("Key", res.key); |
10 |
console.dir("Data", res.value); |
11 |
res.continue(); |
12 |
}
|
13 |
}
|
Penangan sukses dilewatkan objek hasil (res variabel di atas). Ini berisi kunci, objek untuk data (dalam kunci nilai di atas), dan metode lanjutan yang digunakan untuk beralih ke bagian data berikutnya.
Dalam fungsi berikut, kita menggunakan kursor untuk mengulang-ulang semua data objekstore. Karena kita bekerja dengan data "orang", kita menyebutnya sebagai getPeople:
1 |
function getPeople(e) { |
2 |
|
3 |
var s = ""; |
4 |
|
5 |
db.transaction(["people"], "readonly").objectStore("people").openCursor().onsuccess = function(e) { |
6 |
var cursor = e.target.result; |
7 |
if(cursor) { |
8 |
s += "<h2>Key "+cursor.key+"</h2><p>"; |
9 |
for(var field in cursor.value) { |
10 |
s+= field+"="+cursor.value[field]+"<br/>"; |
11 |
}
|
12 |
s+="</p>"; |
13 |
cursor.continue(); |
14 |
}
|
15 |
document.querySelector("#status2").innerHTML = s; |
16 |
}
|
17 |
}
|
Anda dapat melihat demo lengkap ini di unduhan Anda sebagai file test9.html. Ini memiliki logika Add Person seperti pada contoh sebelumnya, jadi cukup buat beberapa orang dan kemudian tekan tombol untuk menampilkan semua data.



Jadi sekarang Anda tahu cara mendapatkan satu bagian data serta cara mendapatkan semua datanya. Sekarang mari kita membahas topik terakhir kita - bekerja dengan indeks.
Mereka Memanggil Ini IndexedDB, Benar?
Kita telah berbicara tentang IndexedDB untuk seluruh artikel tetapi belum benar-benar melakukan apapun - indeks-baik. Indeks adalah bagian penting dari toko objek IndexedDB. Mereka menyediakan cara untuk mengambil data berdasarkan nilai mereka serta menentukan apakah suatu nilai harus unik di dalam toko. Nanti kita akan menunjukkan cara menggunakan indeks untuk mendapatkan berbagai data.
Pertama - bagaimana Anda membuat indeks? Seperti hal-hal lain yang struktural, mereka harus dilakukan dalam acara peningkatan, pada dasarnya pada saat yang sama Anda membuat toko objek Anda. Berikut ini contohnya:
1 |
var objectStore = thisDb.createObjectStore("people", |
2 |
{ autoIncrement:true }); |
3 |
//first arg is name of index, second is the path (col);
|
4 |
objectStore.createIndex("name","name", {unique:false}); |
5 |
objectStore.createIndex("email","email", {unique:true}); |
Di baris pertama kita membuat toko. Kita mengambil hasil itu (objek objectStore) dan menjalankan metode createIndex. Argumen pertama adalah nama untuk indeks dan yang kedua adalah properti yang akan diindeks. Dalam kebanyakan kasus, saya pikir Anda akan menggunakan nama yang sama untuk keduanya. Argumen terakhir adalah serangkaian opsi. Untuk saat ini, kita hanya menggunakan satu, unik. Indeks pertama untuk nama tidak unik. Yang kedua untuk email adalah. Ketika kita menyimpan data, IndexedDB akan memeriksa indeks ini dan memastikan bahwa properti email itu unik. Ini juga akan melakukan beberapa penanganan data di bagian belakang untuk memastikan kita dapat mengambil data dengan indeks ini.
Bagaimana cara kerjanya? Setelah Anda mengambil toko objek melalui transaksi, Anda dapat meminta indeks dari toko itu. Dengan menggunakan kode di atas, berikut ini contohnya:
1 |
var transaction = db.transaction(["people"],"readonly"); |
2 |
var store = transaction.objectStore("people"); |
3 |
var index = store.index("name"); |
4 |
|
5 |
//name is some value
|
6 |
var request = index.get(name); |
Pertama kita mendapatkan transaksi, diikuti oleh toko, dan kemudian indeks. Seperti yang sudah kami katakan sebelumnya, Anda dapat merantai ketiga jalur pertama itu agar lebih ringkas jika Anda mau.
Setelah mendapatkan indeks, Anda dapat melakukan panggilan get untuk mengambil data berdasarkan nama. Kita dapat melakukan sesuatu yang serupa untuk email juga. Hasil dari panggilan itu adalah objek asynchronous lain yang dapat Anda ikat sebagai handler onsuccess. Berikut ini contoh dari handler yang ditemukan di file test10.html:
1 |
request.onsuccess = function(e) { |
2 |
|
3 |
var result = e.target.result; |
4 |
if(result) { |
5 |
var s = "<h2>Name "+name+"</h2><p>"; |
6 |
for(var field in result) { |
7 |
s+= field+"="+result[field]+"<br/>"; |
8 |
}
|
9 |
document.querySelector("#status").innerHTML = s; |
10 |
} else { |
11 |
document.querySelector("#status").innerHTML = "<h2>No match</h2>"; |
12 |
}
|
13 |
}
|
Perhatikan bahwa indeks mendapat panggilan get mengembalikan beberapa objek. Karena nama kita tidak unik, kita mungkin harus memodifikasi kode untuk menangani itu, tetapi itu tidak diperlukan.
Sekarang mari kita menaikannya. Anda telah melihat menggunakan get API pada indeks untuk mendapatkan nilai berdasarkan properti itu. Bagaimana jika Anda ingin mendapatkan kumpulan data yang lebih luas? Istilah terakhir yang akan kita pelajari hari ini adalah Ranges. Rentang adalah cara untuk memilih sub kumpulan indeks. Misalnya, diberi indeks pada properti nama, kita dapat menggunakan rentang untuk menemukan nama yang dimulai dengan A hingga nama yang dimulai dengan C. Rentang datang dalam beberapa varietas yang berbeda. Mereka dapat menjadi "segala sesuatu di bawah beberapa penanda", "semuanya di atas beberapa penanda", dan "sesuatu di antara penanda yang lebih rendah dan penanda yang lebih tinggi." Akhirnya, hanya untuk membuat hal-hal yang menarik, rentang dapat bersifat inklusif atau eksklusif. Pada dasarnya itu berarti untuk rentang yang berasal dari A-C, kita dapat menentukan apakah kita ingin memasukkan A dan C dalam rentang atau hanya nilai di antara mereka. Akhirnya, Anda juga dapat meminta rentang naik dan turun.
Rentang dibuat menggunakan objek tingkat atas yang disebut IDBKeyRange. Ini memiliki tiga metode yang menarik: lowerBound, upperBound, dan bound. lowerBound digunakan untuk membuat rentang yang dimulai dengan nilai yang lebih rendah dan mengembalikan semua data "di atas" itu. upperBound adalah kebalikannya. Dan - akhirnya - bound digunakan untuk mendukung satu set data dengan batas bawah dan atas. Mari kita lihat beberapa contoh:
1 |
//Values over 39
|
2 |
var oldRange = IDBKeyRange.lowerBound(39); |
3 |
|
4 |
//Values 40a dn over
|
5 |
var oldRange2 = IDBKeyRange.lowerBound(40,true); |
6 |
|
7 |
//39 and smaller...
|
8 |
var youngRange = IDBKeyRange.upperBound(40); |
9 |
|
10 |
//39 and smaller...
|
11 |
var youngRange2 = IDBKeyRange.upperBound(39,true); |
12 |
|
13 |
//not young or old... you can also specify inclusive/exclusive
|
14 |
var okRange = IDBKeyRange.bound(20,40) |
Setelah Anda memiliki rentang, Anda dapat meneruskannya ke metode openCursor indeks. Ini memberi Anda iterator untuk mengulang nilai yang cocok dengan rentang tersebut. Sebagai cara praktis, ini sebenarnya bukan pencarian. Anda dapat menggunakan ini untuk mencari konten berdasarkan awal string, tetapi bukan di tengah atau akhir. Mari kita lihat contoh lengkapnya. Pertama kita akan membuat formulir sederhana untuk mencari orang:
1 |
Starting with: <input type="text" id="nameSearch" placeholder="Name"><br/> |
2 |
Ending with: <input type="text" id="nameSearchEnd" placeholder="Name"><br/> |
3 |
<button id="getButton">Get By Name Range</button> |
Kitab akan mengizinkan pencarian yang terdiri dari salah satu dari tiga jenis rentang (sekali lagi, nilai dan lebih tinggi, nilai tertinggi, atau nilai dalam dua input). Sekarang mari kita lihat event handler untuk formulir ini.
1 |
function getPeople(e) { |
2 |
var name = document.querySelector("#nameSearch").value; |
3 |
|
4 |
var endname = document.querySelector("#nameSearchEnd").value; |
5 |
|
6 |
if(name == "" && endname == "") return; |
7 |
|
8 |
var transaction = db.transaction(["people"],"readonly"); |
9 |
var store = transaction.objectStore("people"); |
10 |
var index = store.index("name"); |
11 |
|
12 |
//Make the range depending on what type we are doing
|
13 |
var range; |
14 |
if(name != "" && endname != "") { |
15 |
range = IDBKeyRange.bound(name, endname); |
16 |
} else if(name == "") { |
17 |
range = IDBKeyRange.upperBound(endname); |
18 |
} else { |
19 |
range = IDBKeyRange.lowerBound(name); |
20 |
}
|
21 |
|
22 |
var s = ""; |
23 |
|
24 |
index.openCursor(range).onsuccess = function(e) { |
25 |
var cursor = e.target.result; |
26 |
if(cursor) { |
27 |
s += "<h2>Key "+cursor.key+"</h2><p>"; |
28 |
for(var field in cursor.value) { |
29 |
s+= field+"="+cursor.value[field]+"<br/>"; |
30 |
}
|
31 |
s+="</p>"; |
32 |
cursor.continue(); |
33 |
}
|
34 |
document.querySelector("#status").innerHTML = s; |
35 |
}
|
36 |
|
37 |
}
|
Dari atas ke bawah - kita mulai dengan meraih dua kolom formulir. Selanjutnya kita buat transaksi dan dari situ dapatkan toko dan indeks. Sekarang untuk bagian semi-kompleks. Karena kita memiliki tiga jenis rentang yang berbeda yang perlu kita dukung, kita harus melakukan sedikit logika kondisional untuk mencari tahu yang kita perlukan. Rentang apa yang kami buat didasarkan pada bidang apa yang Anda isi. Apa yang baik adalah bahwa begitu kita memiliki jangkauan, maka kita hanya meneruskannya ke indeks dan membuka kursor. Itu dia! Anda dapat menemukan contoh lengkap ini di test11.html. Pastikan untuk memasukkan beberapa nilai terlebih dahulu sehingga Anda memiliki data untuk mencari.
Apa berikutnya?
Percaya atau tidak - kita baru memulai diskusi kita di IndexedDB. Di artikel berikutnya, kita akan membahas topik tambahan, termasuk pembaruan dan penghapusan, nilai berbasis larik, dan beberapa kiat umum untuk bekerja dengan IndexedDB.



