IndexedDB
IndexedDB โ brauzer ichiga o'rnatilgan kuchli ma'lumotlar bazasi. U localStoragedan ancha kuchliroq: katta hajmli ma'lumot saqlaydi, murakkab so'rovlar va indekslarni qo'llab-quvvatlaydi, hamda deyarli har qanday turdagi qiymatni (obyektlar, fayllar, Bloblar) saqlay oladi. U tranzaksiyalar asosida ishlaydi va katta oflayn ilovalar uchun mo'ljallangan.
IndexedDB nima uchun kerak
localStorage oddiy, ammo cheklangan: faqat satr saqlaydi, ~5 MB bilan chegaralangan va sinxron. IndexedDB esa quyidagilarni beradi:
- Katta hajmli saqlash (yuzlab megabayt yoki undan ko'p);
- Deyarli har qanday tur โ obyektlar, massivlar,
Blob,File, hattokiDate; - Kalit bo'yicha tez qidiruv va indekslar orqali boshqa maydonlar bo'yicha qidiruv;
- Tranzaksiyalar โ ma'lumot izchilligini kafolatlaydi;
- Asinxron API โ interfeys qotib qolmaydi.
indexedDB ob'yekti mavjud emas โ quyidagi barcha misollar faqat brauzerda ishlaydi.Bazani ochish va versiya
Ish indexedDB.open(nom, versiya) bilan boshlanadi. U bazani ochadi (yo'q bo'lsa yaratadi) va so'rov (request) obyektini qaytaradi:
// Brauzerda:
let openRequest = indexedDB.open('shop', 1);
openRequest.onsuccess = function() {
let db = openRequest.result;
console.log('Baza ochildi:', db.name);
};
openRequest.onerror = function() {
console.error('Xato:', openRequest.error);
};
Ikkinchi argument โ versiya raqami (musbat butun son). Sxema (obyekt omborlari, indekslar) faqat versiya oshirilganda o'zgartiriladi. Versiya oshirilganda upgradeneeded hodisasi ishga tushadi โ sxemani aynan shu yerda quramiz:
let openRequest = indexedDB.open('shop', 1);
openRequest.onupgradeneeded = function() {
let db = openRequest.result;
// sxema o'zgarishlari shu yerda:
if (!db.objectStoreNames.contains('books')) {
db.createObjectStore('books', { keyPath: 'id' });
}
};
upgradeneeded ichida mumkin. Oddiy onsuccess ichida buni qilib bo'lmaydi. Sxema o'zgarganda versiya raqamini oshirishingiz kerak.Obyekt ombori (object store)
Obyekt ombori โ IndexedDB'da ma'lumot saqlanadigan asosiy tuzilma, xuddi SQL'dagi "jadval"ga o'xshaydi. U kalit bo'yicha qiymatlarni saqlaydi. Har bir omborda kalit qanday aniqlanishini belgilaymiz:
openRequest.onupgradeneeded = function() {
let db = openRequest.result;
// keyPath: obyektning maydoni kalit bo'ladi
db.createObjectStore('books', { keyPath: 'id' });
// yoki avtomatik oshib boruvchi kalit:
// db.createObjectStore('logs', { autoIncrement: true });
};
keyPathโ saqlanadigan obyektning qaysi maydoni kalit bo'lishini ko'rsatadi (masalan'id');autoIncrement: trueโ har bir yozuvga avtomatik oshib boradigan raqam kalit sifatida beriladi;- Ikkalasini ham ko'rsatmasa, kalit har
put/addda alohida beriladi.
put bilan saqlash mavjudini almashtiradi, add bilan esa xatolik beradi.Tranzaksiya (transaction)
IndexedDB'da har qanday o'qish yoki yozish tranzaksiya ichida bajariladi. Tranzaksiya โ bu bir yoki bir nechta amalni atomar (butun holda muvaffaqiyatli yoki butun holda bekor) bajaruvchi guruh. db.transaction(omborlar, rejim) bilan yaratiladi:
// faqat o'qish uchun:
let tx = db.transaction('books', 'readonly');
// o'qish va yozish uchun:
let tx = db.transaction('books', 'readwrite');
// omborni olamiz:
let store = tx.objectStore('books');
'readonly'โ faqat o'qish (standart). Bir vaqtda ko'p o'qish tranzaksiyalari parallel ishlashi mumkin;'readwrite'โ o'qish va yozish. Bir ombor uchun bir vaqtda faqat bitta yozish tranzaksiyasi ishlaydi.
// tranzaksiya tugashini kuzatish:
tx.oncomplete = function() {
console.log('Tranzaksiya tugadi');
};
tx.onabort = function() {
console.log('Tranzaksiya bekor qilindi:', tx.error);
};
readwriteni faqat kerak bo'lganda ishlating. Ortiqcha readwrite tranzaksiyalar boshqa yozishlarni bloklab, ilovani sekinlashtiradi.Qo'shish va o'qish
Ombor obyektini olganimizdan so'ng, unga add/put bilan yozamiz va get bilan o'qiymiz. Har bir amal so'rov (request) qaytaradi:
let tx = db.transaction('books', 'readwrite');
let store = tx.objectStore('books');
let book = { id: 1, title: 'JavaScript', price: 100 };
let request = store.add(book);
request.onsuccess = function() {
console.log('Qo'shildi, kalit:', request.result);
};
request.onerror = function() {
console.log('Xato:', request.error);
};
O'qish kalit bo'yicha amalga oshiriladi:
let tx = db.transaction('books', 'readonly');
let store = tx.objectStore('books');
let request = store.get(1);
request.onsuccess = function() {
let book = request.result;
if (book) {
console.log(book.title); // "JavaScript"
} else {
console.log('Topilmadi');
}
};
Foydali metodlar:
add(value)โ qo'shadi (kalit mavjud bo'lsa xatolik);put(value)โ qo'shadi yoki mavjudini almashtiradi;get(key)โ kalit bo'yicha bittasini oladi;getAll()โ barcha yozuvlarni oladi;delete(key)โ kalit bo'yicha o'chiradi;clear()โ omborni butunlay bo'shatadi.
Indekslar
Standart holatda IndexedDB'da faqat kalit bo'yicha qidirish mumkin. Boshqa maydon bo'yicha qidirish uchun indeks yaratamiz. Indeks โ bu ma'lum maydon bo'yicha saralangan qo'shimcha "jadval":
openRequest.onupgradeneeded = function() {
let db = openRequest.result;
let store = db.createObjectStore('books', { keyPath: 'id' });
// 'price' maydoni bo'yicha indeks:
store.createIndex('price_idx', 'price', { unique: false });
};
Endi indeks orqali narx bo'yicha qidirish mumkin:
let tx = db.transaction('books', 'readonly');
let store = tx.objectStore('books');
let index = store.index('price_idx');
// narxi aynan 100 bo'lganlarni olish:
let request = index.getAll(100);
request.onsuccess = function() {
console.log(request.result); // narxi 100 bo'lgan kitoblar
};
- Ikkinchi argument (
'price') โ indekslanadigan maydon (keyPath); unique: trueโ bu maydon qiymatlari noyob bo'lishi shart;- Indeks
IDBKeyRangebilan oraliq so'rovlarni ham qo'llab-quvvatlaydi (masalan narxi 50-150 orasida).
upgradeneeded ichida yaratiladi.getAll va IDBKeyRange
Ko'p yozuvni bir vaqtda olish uchun getAll juda qulay. Oraliq bo'yicha filtrlash uchun IDBKeyRange ishlatiladi:
let index = store.index('price_idx');
// narxi 50 dan 150 gacha (chegaralar bilan):
let range = IDBKeyRange.bound(50, 150);
let request = index.getAll(range);
request.onsuccess = function() {
console.log(request.result);
};
// boshqa oraliqlar:
// IDBKeyRange.lowerBound(100) -> 100 va undan katta
// IDBKeyRange.upperBound(100) -> 100 va undan kichik
// IDBKeyRange.only(100) -> aynan 100
Promise o'ramchisi
IndexedDB'ning tabiiy API'si hodisalarga (onsuccess/onerror) asoslangan bo'lib, bu kodni murakkablashtiradi. Har bir so'rovni Promisega o'rab, async/await bilan ishlatish ancha qulay. Quyida oddiy o'ramchi:
function promisify(request) {
return new Promise(function(resolve, reject) {
request.onsuccess = function() {
resolve(request.result);
};
request.onerror = function() {
reject(request.error);
};
});
}
// ishlatish (async funksiya ichida):
async function getBook(db, id) {
let tx = db.transaction('books', 'readonly');
let store = tx.objectStore('books');
let book = await promisify(store.get(id));
return book;
}
Bazani ochishni ham Promise'ga o'rash mumkin:
function openDB(name, version, onUpgrade) {
return new Promise(function(resolve, reject) {
let request = indexedDB.open(name, version);
request.onupgradeneeded = function() {
onUpgrade(request.result);
};
request.onsuccess = function() {
resolve(request.result);
};
request.onerror = function() {
reject(request.error);
};
});
}
idb kutubxonasini ishlatadi โ u aynan shunday Promise o'ramchisini tayyor holda beradi va IndexedDB bilan ishlashni sezilarli soddalashtiradi.O'chirish va bazani tozalash
// bitta yozuvni o'chirish:
let tx = db.transaction('books', 'readwrite');
tx.objectStore('books').delete(1);
// omborni butunlay bo'shatish:
tx.objectStore('books').clear();
// butun bazani o'chirish:
let delReq = indexedDB.deleteDatabase('shop');
delReq.onsuccess = function() {
console.log('Baza o'chirildi');
};
Qachon IndexedDB kerak
IndexedDB kuchli, lekin murakkab. Uni tanlashda quyidagilarni hisobga oling:
- Katta hajm โ
localStoragening ~5 MB chegarasidan oshadigan ma'lumot bo'lsa; - Murakkab qidiruv โ indekslar va oraliq so'rovlar kerak bo'lsa;
- Oflayn ilovalar โ PWA'lar, oflayn ishlaydigan ilovalar, keshlar;
- Turli xil ma'lumot โ fayllar,
Blob, katta obyektlar saqlash kerak bo'lsa.
Aksincha, oddiy holatlar uchun soddaroq vositalar mos:
- Bir nechta sozlama saqlash โ
localStorage; - Serverga yuboriladigan sessiya identifikatori โ cookie;
- Vaqtinchalik, bitta tab'ga tegishli holat โ
sessionStorage.
localStorage yetarli va ancha sodda.Xulosa
- IndexedDB โ brauzerdagi kuchli, asinxron, tranzaksiyaga asoslangan ma'lumotlar bazasi;
indexedDB.open(nom, versiya)bilan ochiladi; sxema faqatupgradeneededichida quriladi;- Ma'lumot obyekt omborlarida saqlanadi; kalit
keyPathyokiautoIncrementorqali aniqlanadi; - Har bir amal tranzaksiya ichida bajariladi (
readonlyyokireadwrite); add/put/get/getAll/deleteasosiy amallar;- Indekslar boshqa maydonlar bo'yicha qidiruvni beradi;
- Hodisali API'ni
Promisega o'rabasync/awaitbilan ishlatish qulay (yokiidbkutubxonasi); - IndexedDB katta va murakkab ma'lumot uchun; oddiy holatda
localStorageyoki cookie yetarli.