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