أفضل الممارسات للحفاظ على حالة التطبيق باستخدام IndexedDB

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

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

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

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

الحفاظ على سلوك التطبيق المتوقّع

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

الاستنتاجات

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

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

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