الغوص في IndexedDB

تعد IndexedDB إحدى إمكانيات التخزين المقدمة في المتصفحات على مر السنين. إليك مقدمة إلى IndexedDB ، قاعدة بيانات الويب التي تدعمها جميع المتصفحات الحديثة

مقدمة إلى قاعدة البيانات المفهرسة

تعد IndexedDB إحدى إمكانيات التخزين المقدمة في المتصفحات على مر السنين. إنه مخزن مفتاح / قيمة (قاعدة بيانات noSQL) يعتبر كذلكالحل النهائي لتخزين البيانات في المتصفحات.

إنها واجهة برمجة تطبيقات غير متزامنة ، مما يعني أن إجراء عمليات مكلفة لن يمنع مؤشر ترابط واجهة المستخدم الذي يوفر تجربة قذرة للمستخدمين. يمكنه تخزين كمية غير محددة من البيانات ، على الرغم من أنه بمجرد تجاوز حد معين ، يُطلب من المستخدم إعطاء الموقع حدودًا أعلى.

إنهمدعوم على جميع المتصفحات الحديثة.

وهو يدعم المعاملات وإصدار الإصدارات ويعطي أداءً جيدًا.

داخل المتصفح يمكننا أيضًا استخدام:

  • بسكويت: يمكن أن تستضيف كمية صغيرة جدًا من السلاسل
  • تخزين الويب(أو DOM Storage) ، وهو مصطلح يعرّف عادةً localStorage و sessionStorage ، وهما مخزنان للمفتاح / القيمة. جلسة التخزين ، لا تحتفظ بالبيانات ، والتي يتم مسحها عند انتهاء الجلسة ، بينما يحتفظ localStorage بالبيانات عبر الجلسات

من عيوب التخزين المحلي / التخزين في الجلسة أن يتم تحديده بحجم صغير (وغير متسق) ، حيث يوفر تنفيذ المتصفحات مساحة تتراوح من 2 ميجابايت إلى 10 ميجابايت لكل موقع.

في الماضي كان لدينا أيضاSQL الويب، التفاف حول SQLite ، ولكن هذا الآنإهمالوغير مدعوم في بعض المتصفحات الحديثة ، لم يكن أبدًا معيارًا معترفًا به ولذلك لا ينبغي استخدامه ، على الرغم من أن 83٪ من المستخدمين لديهم هذه التقنية على أجهزتهموفقًا لـ Can I Use.

بينما يمكنك إنشاء قواعد بيانات متعددة تقنيًا لكل موقع ، فإنك عمومًاإنشاء قاعدة بيانات واحدة، وداخل قاعدة البيانات يمكنك إنشاءمخازن كائن متعددة.

قاعدة البيانات هيخاص بالمجال، لذلك لا يمكن لأي موقع آخر الوصول إلى موقع ويب آخر لمتاجر IndexedDB.

يحتوي كل متجر عادة على مجموعة منأشياء، التي يمكن أن تكون

  • سلاسل
  • أعداد
  • شاء
  • المصفوفات
  • تواريخ

على سبيل المثال ، قد يكون لديك متجر يحتوي على منشورات وآخر يحتوي على تعليقات.

يحتوي المتجر على عدد من العناصر التي لها مفتاح فريد ، والذي يمثل الطريقة التي يمكن من خلالها التعرف على الكائن.

يمكنك تغيير تلك المتاجر باستخدام المعاملات ، عن طريق إجراء عمليات الإضافة والتعديل والحذف ، والتكرار على العناصر التي تحتوي عليها.

منذ قدوموعودفي ES6 ، والانتقال اللاحق لواجهات برمجة التطبيقات إلى استخدام الوعود ، تبدو واجهة برمجة تطبيقات IndexedDB قليلاًمدرسة قديمة.

بينما لا يوجد شيء خاطئ في ذلك ، في جميع الأمثلة التي سأشرحها سأستخدم ملفالمكتبة الموعودة IndexedDBبواسطة Jake Archibald ، وهي طبقة صغيرة أعلى واجهة برمجة تطبيقات IndexedDB لتسهيل استخدامها.

تُستخدم هذه المكتبة أيضًا في جميع الأمثلة الموجودة على موقع Google Developers فيما يتعلق بقاعدة البيانات المفهرسة

إنشاء قاعدة بيانات مفهرسة

إن أبسط طريقة هي الاستخدامunpkg، من خلال إضافة هذا إلى رأس الصفحة:

<script type="module">
import { openDB, deleteDB } from 'https://unpkg.com/idb?module'
</script>

قبل استخدام IndexedDB API ، تأكد دائمًا من التحقق من الدعم في المتصفح ، على الرغم من توفره على نطاق واسع ، فأنت لا تعرف أبدًا أي متصفح يستخدمه المستخدم:

(() => {
  'use strict'

if (!(‘indexedDB’ in window)) { console.warn(‘IndexedDB not supported’) return }

//…IndexedDB code })()

كيفإنشاء قاعدة بيانات

استخدامopenDB():

(async () => {
  //...

  const dbName = 'mydbname'
  const storeName = 'store1'
  const version = 1 //versions start at 1

  const db = await openDB(dbName, version, {
    upgrade(db, oldVersion, newVersion, transaction) {
      const store = db.createObjectStore(storeName)
    }
  })
})()

المعلمتان الأوليان هما اسم قاعدة البيانات والإصدار. المعلمة الثالثة ، وهي اختيارية ، هي كائن يحتوي على وظيفةيتم استدعاؤه فقط إذا كان رقم الإصدار أعلى من إصدار قاعدة البيانات المثبتة حاليًا. في جسم الوظيفة ، يمكنك ترقية البنية (المخازن والفهارس) لـ db.

إضافة البيانات إلى المتجر

إضافة البيانات عند إنشاء المتجر وتهيئته

أنت تستخدمputطريقة تخزين الكائن ، لكننا نحتاج أولاً إلى مرجع لها ، والذي يمكننا الحصول عليه منdb.createObjectStore()عندما نقوم بإنشائه.

عند استخدامput، القيمة هي الوسيطة الأولى ، المفتاح هو الثاني. هذا لأنه إذا حددتkeyPathعند إنشاء ملف تخزين العناصر ، لا تحتاج إلى إدخال اسم المفتاح في كل طلب put () ، يمكنك فقط كتابة القيمة.

هذا يسكنstore0بمجرد إنشائه:

(async () => {
  //...
  const dbName = 'mydbname'
  const storeName = 'store0'
  const version = 1

const db = await openDB(dbName, version,{ upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) store.put(‘Hello world!’, ‘Hello’) } }) })()

إضافة البيانات عند إنشاء المتجر بالفعل باستخدام المعاملات

لإضافة عناصر في وقت لاحق على الطريق ، تحتاج إلى إنشاء قراءة / كتابةعملية تجارية، الذي يضمن تكامل قاعدة البيانات (إذا فشلت عملية ما ، يتم إرجاع جميع العمليات في المعاملة إلى الوراء وتعود الحالة إلى حالة معروفة).

لذلك ، استخدم إشارة إلىdbPromiseالشيء الذي حصلنا عليه عند الاتصالopenDB، و اهرب:

(async () => {
  //...
  const dbName = 'mydbname'
  const storeName = 'store0'
  const version = 1

const db = await openDB(/* … */)

const tx = db.transaction(storeName, ‘readwrite’) const store = await tx.objectStore(storeName)

const val = ‘hey!’ const key = ‘Hello again’ const value = await store.put(val, key) await tx.done })()

الحصول على البيانات من متجر

الحصول على عنصر واحد من متجر:get()

const key = 'Hello again'
const item = await db.transaction(storeName).objectStore(storeName).get(key)

الحصول على جميع العناصر من متجر:getAll()

احصل على جميع المفاتيح المخزنة

const items = await db.transaction(storeName).objectStore(storeName).getAllKeys()

احصل على جميع القيم المخزنة

const items = await db.transaction(storeName).objectStore(storeName).getAll()

حذف البيانات من قاعدة البيانات المفهرسة

حذف قاعدة البيانات ومخزن العناصر والبيانات

حذف قاعدة بيانات IndexedDB بأكملها

const dbName = 'mydbname'
await deleteDB(dbName)

لحذف البيانات في ملف تخزين العناصر

نحن نستخدم معاملة:

(async () => {
  //...

  const dbName = 'mydbname'
  const storeName = 'store1'
  const version = 1

const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { const store = db.createObjectStore(storeName) } })

const tx = await db.transaction(storeName, ‘readwrite’) const store = await tx.objectStore(storeName)

const key = ‘Hello again’ await store.delete(key) await tx.done })()

الترحيل من الإصدار السابق لقاعدة البيانات

المعلمة الثالثة (الاختيارية) لملفopenDB()الوظيفة هي كائن يمكن أن يحتوي علىupgradeوظيفةيتم استدعاؤه فقط إذا كان رقم الإصدار أعلى من إصدار قاعدة البيانات المثبتة حاليًا. في هيئة الوظيفة هذه ، يمكنك ترقية البنية (المخازن والفهارس) لـ db:

const name = 'mydbname'
const version = 1
openDB(name, version, {
  upgrade(db, oldVersion, newVersion, transaction) {
    console.log(oldVersion)
  }
})

في رد الاتصال هذا ، يمكنك التحقق من الإصدار الذي يقوم المستخدم بتحديثه ، وتنفيذ بعض العمليات وفقًا لذلك.

يمكنك إجراء ترحيل من إصدار قاعدة بيانات سابق باستخدام بناء الجملة هذا

(async () => {
  //...
  const dbName = 'mydbname'
  const storeName = 'store0'
  const version = 1

const db = await openDB(dbName, version, { upgrade(db, oldVersion, newVersion, transaction) { switch (oldVersion) { case 0: // no db created before // a store introduced in version 1 db.createObjectStore(‘store1’) case 1: // a new store in version 2 db.createObjectStore(‘store2’, { keyPath: ‘name’ }) } db.createObjectStore(storeName) } }) })()

مفاتيح فريدة

createObjectStore()كما ترى فيcase 1يقبل معلمة ثانية تشير إلى مفتاح الفهرس لقاعدة البيانات. هذا مفيد جدًا عند تخزين العناصر:put()لا تحتاج المكالمات إلى معلمة ثانية ، ولكن يمكنها فقط أن تأخذ القيمة (كائن) وسيتم تعيين المفتاح إلى خاصية الكائن التي تحمل هذا الاسم.

يمنحك الفهرس طريقة لاسترداد قيمة لاحقًا بواسطة هذا المفتاح المحدد ، ويجب أن يكون فريدًا (يجب أن يكون لكل عنصر مفتاح مختلف)

يمكن تعيين مفتاح على زيادة تلقائية ، لذلك لا تحتاج إلى تتبعه على رمز العميل:

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

استخدم الزيادة التلقائية إذا كانت قيمك لا تحتوي على مفتاح فريد بالفعل (على سبيل المثال ، إذا قمت بجمع عناوين البريد الإلكتروني بدون اسم مرتبط).

تحقق من وجود متجر

يمكنك التحقق مما إذا كان ملف تخزين العناصر موجودًا بالفعل عن طريق استدعاءobjectStoreNames()طريقة:

const storeName = 'store1'

if (!db.objectStoreNames.contains(storeName)) { db.createObjectStore(storeName) }

الحذف من IndexedDB

حذف قاعدة البيانات ومخزن العناصر والبيانات

احذف قاعدة البيانات

await deleteDB('mydb')

حذف ملف تخزين العناصر

لا يمكن حذف ملف تخزين العناصر إلا في رد الاتصال عند فتح db ، ولا يتم استدعاء رد النداء هذا إلا إذا قمت بتحديد إصدار أعلى من الإصدار المثبت حاليًا:

const db = await openDB('dogsdb', 2, {
  upgrade(db, oldVersion, newVersion, transaction) {
    switch (oldVersion) {
      case 0: // no db created before
        // a store introduced in version 1
        db.createObjectStore('store1')
      case 1:
        // delete the old store in version 2, create a new one
        db.deleteObjectStore('store1')
        db.createObjectStore('store2')
    }
  }
})

لحذف البيانات في ملف تخزين العناصر ، استخدم معاملة

const key = 232 //a random key

const db = await openDB(/*...*/)
const tx = await db.transaction('store', 'readwrite')
const store = await tx.objectStore('store')
await store.delete(key)
await tx.complete

هناك المزيد!

هذه هي الأساسيات فقط. لم أتحدث عن المؤشرات والأشياء الأكثر تقدمًا. هناك المزيد في IndexedDB ولكن آمل أن يمنحك هذا السبق.


المزيد من دروس المتصفح: