أفضل الممارسات لاستخدام IndexedDB

تعرف على أفضل الممارسات لمزامنة حالة التطبيق بين IndexedDB ومكتبات إدارة حالة شائعة.

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

تخزين حالة التطبيق في يمكن أن تكون دالة IndexedDB طريقة رائعة لزيادة سرعة وقت التحميل للزيارات المتكررة. يمكن للتطبيق بعد ذلك المزامنة مع أي خدمات واجهة برمجة تطبيقات في الخلفية. وتحديث واجهة المستخدم ببيانات جديدة بشكل كسول، باستخدام stale-أثناء- إعادة التحقّق.

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

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

توفير إمكانية توقّع تطبيقك

تنشأ الكثير من التعقيدات حول قاعدة البيانات المفهرسة بسبب كثرة العوامل (المطوّر) لا تتحكم فيها. يستكشف هذا القسم العديد من المشاكل التي يجب وضعها في الاعتبار عند العمل باستخدام قاعدة البيانات المفهرسة.

لا يمكن تخزين كل شيء في IndexedDB على جميع الأنظمة الأساسية

في حال تخزين ملفات كبيرة من إنشاء المستخدمين، مثل الصور أو الفيديوهات، يمكنك محاولة تخزينها. ككائنات File أو Blob. سيعمل ذلك على بعض الأنظمة الأساسية لكنه لا ينجح على أنظمة أخرى. تفعيل Safari لا يمكن لنظام التشغيل iOS على وجه التحديد تخزين Blob في IndexedDB.

لحسن الحظ ليس من الصعب جدًا تحويل Blob إلى ArrayBuffer، والعكس صحيح. التخزين تتوافق ArrayBuffer في IndexedDB بشكل جيد للغاية.

مع ذلك، تذكَّر أنّ Blob يتضمّن نوع MIME بينما لا يتوفّر للنوع ArrayBuffer. عليك إجراء ما يلي: بتخزين النوع إلى جانب المخزن المؤقت لإجراء التحويل بشكل صحيح.

لتحويل ArrayBuffer إلى Blob، يمكنك ببساطة استخدام الدالة الإنشائية Blob.

function arrayBufferToBlob(buffer, type) {
  return new Blob([buffer], { type: type });
}

أما الاتجاه الآخر فهو أكثر تعقيدًا قليلاً، ويُعد عملية غير متزامنة. يمكنك استخدام كائن FileReader لقراءة الكائن الثنائي الكبير (blob) كـ ArrayBuffer. عند انتهاء القراءة، loadend في القارئ. يمكنك إكمال هذه العملية باستخدام Promise على النحو التالي:

function blobToArrayBuffer(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('loadend', () => {
      resolve(reader.result);
    });
    reader.addEventListener('error', reject);
    reader.readAsArrayBuffer(blob);
  });
}

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

قد تحدث الأخطاء عند الكتابة في IndexedDB لأسباب مختلفة، وفي بعض الحالات قد تحدث الأسباب خارجة عن سيطرتك كمطوّر برامج. على سبيل المثال، لا تسمح بعض المتصفحات حاليًا الكتابة في IndexedDB أثناء استخدام وضع التصفُّح بخصوصية تامّة. كما أن هناك احتمال أن يكون المستخدم يستخدم جهازًا أوشكت مساحة القرص على النفاد، المتصفح إلى منعك من تخزين أي شيء على الإطلاق.

ولهذا السبب، من المهم للغاية أن تقوم دائمًا بتنفيذ التعامل المناسب مع الأخطاء في رمز قاعدة البيانات المفهرسة. هذا يعني أيضًا أنه من الجيد عمومًا أن تحتفظ بحالة التطبيق في الذاكرة (في بالإضافة إلى تخزينها)، حتى لا تتعطّل واجهة المستخدم عند التشغيل في وضع التصفّح بخصوصية تامّة أو عند مساحة التخزين غير متاحة (حتى لو لم تتوفر بعض ميزات التطبيقات الأخرى التي تتطلب سعة تخزين) العمل).

يمكنك رصد الأخطاء في عمليات IndexedDB عن طريق إضافة معالج أحداث لحدث error. عند إنشاء عنصر IDBDatabase أو IDBTransaction أو IDBRequest.

const request = db.open('example-db', 1);
request.addEventListener('error', (event) => {
  console.log('Request error:', request.error);
};

يُحتمَل أنّ المستخدم قد عدَّل أو حذف البيانات المخزَّنة.

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

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

قد تكون البيانات المخزنة قديمة

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

تتوافق أداة IndexedDB مع إصدارات المخططات والترقية من خلال IDBOpenDBRequest.onupgradeneeded() الطريقة؛ ومع ذلك، ستظل بحاجة إلى كتابة رمز الترقية على نحو يتيح له التعامل مع بيانات المستخدم يعود إلى إصدار سابق (بما في ذلك إصدار به خطأ).

قد تكون اختبارات الوحدات مفيدة للغاية هنا، إذ لا يكون من الممكن غالبًا اختبار كل النتائج الممكنة يدويًا مسارات وحالات الترقية.

الحفاظ على أداء تطبيقك

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

كقاعدة عامة، يجب ألا تكون قيمة القراءة والكتابة في IndexedDB أكبر مما هو مطلوب للبيانات. الوصول إليه.

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

ويطرح ذلك بعض التحديات عند التخطيط لكيفية الاحتفاظ بحالة التطبيق في IndexedDB، حيث إن معظم من مكتبات إدارة الدولة الشائعة (مثل Redux) عن طريق إدارة شجرة الولاية بالكامل ككائن JavaScript واحد.

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

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

وينطبق ذلك أيضًا في حال تخزين عناصر كبيرة مثل الصور أو الموسيقى أو الفيديو في IndexedDB. تخزين كل عنصر بمفتاحه الخاص بدلاً من داخل كائن أكبر، بحيث يمكنك استرداد البيانات المنظمة دون دفع تكلفة استرداد الملف الثنائي أيضًا.

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

أخيرًا، عليك دائمًا قياس تأثير الأداء من التعليمات البرمجية التي تكتبها. صحيح أنّ عمليات الكتابة الصغيرة في IndexedDB ستحقق أداءً أفضل من عمليات الكتابة الكبيرة. فإن هذا مهم فقط إذا كانت عمليات الكتابة إلى IndexedDB التي يؤديها التطبيق تؤدي بالفعل إلى مهام طويلة التي تحظر سلسلة التعليمات الرئيسية وتؤدّي إلى خفض مستوى تجربة المستخدم. من المهم القياس حتى فهم الغرض الذي تحسِّن الأداء من أجله

الاستنتاجات

يمكن لمطوّري البرامج الاستفادة من آليات تخزين العميل مثل IndexedDB لتحسين تجربة المستخدم تطبيقها ليس فقط من خلال الحفاظ على الحالة عبر الجلسات ولكن أيضًا عن طريق تقليل الوقت لتحميل الحالة الأولية في الزيارات المتكررة.

يمكن أن يؤدي استخدام أداة IndexedDB بشكل صحيح إلى تحسين تجربة المستخدم بشكل كبير، إلا أن استخدامها بشكل غير صحيح أو يمكن أن يؤدي عدم التعامل مع حالات الخطأ إلى تعطل التطبيقات وعدم رضا المستخدمين.

نظرًا لأن تخزين العميل يتضمن العديد من العوامل خارجة عن سيطرتك، فمن الأهمية بمكان أن تكون التعليمة البرمجية الخاصة بك اختباره ومعالجة الأخطاء بشكل صحيح، حتى تلك التي قد يبدو من غير المرجح حدوثها في البداية.