تتوفّر العديد من الخيارات المختلفة لتخزين البيانات في المتصفّح. أيّ منهما هو الأنسب لاحتياجاتك؟
قد تكون اتصالات الإنترنت غير مستقرة أو غير متوفرة أثناء التنقل، ولهذا السبب، تُعد إمكانية الاستخدام بلا إنترنت والأداء الموثوق من الميزات الشائعة في تطبيقات الويب التقدّمية. حتى في بيئات الاتصال اللاسلكي المثالية، يمكن أن يؤدي الاستخدام الحكيم للتخزين المؤقت وتقنيات التخزين الأخرى إلى تحسين تجربة المستخدم بشكل كبير. تتوفّر عدة طرق للاحتفاظ بنسخة مؤقتة من موارد التطبيق الثابتة (HTML وJavaScript وCSS والصور وغيرها) والبيانات (بيانات المستخدمين والمقالات الإخبارية وغيرها). ولكن ما هو الحل الأفضل؟ ما هو حجم التخزين المتاح لك؟ كيف يمكن منع إزالة الجهاز؟
ما هي الأداة التي يجب استخدامها؟
في ما يلي اقتراح عام لتخزين الموارد:
- بالنسبة إلى موارد الشبكة اللازمة لتحميل تطبيقك، استخدِم واجهة برمجة التطبيقات Cache Storage API (وهي جزء من برامج الخدمة).
- بالنسبة إلى المحتوى المستند إلى الملفات، استخدِم نظام الملفات الخاص بالمصدر (OPFS).
- بالنسبة إلى البيانات الأخرى، استخدِم IndexedDB (مع برنامج تضمين للوعود).
تتوافق IndexedDB وOPFS وCache Storage API مع جميع المتصفّحات الحديثة.
وهي غير متزامنة، ولن تحظر سلسلة التعليمات الرئيسية (ولكن يتوفّر أيضًا نوع متزامن من نظام الملفات الخاص بنطاق المصدر فقط في برامج Web Workers). ويمكن الوصول إليها من خلال العنصر window وWeb Workers وService Workers، ما يتيح استخدامها في أي مكان في الرمز.
ماذا عن آليات التخزين الأخرى؟
تتوفّر آليات تخزين أخرى في المتصفّح، ولكن استخدامها محدود وقد تتسبّب في حدوث مشاكل كبيرة في الأداء.
SessionStorage خاص بعلامة التبويب، ويقتصر نطاقه على مدة بقاء علامة التبويب. وقد يكون مفيدًا لتخزين كميات صغيرة من المعلومات الخاصة بالجلسة، مثل مفتاح IndexedDB. يجب استخدامها بحذر لأنّها متزامنة وستحظر سلسلة التعليمات الرئيسية. ويقتصر حجمه على 5 ميغابايت تقريبًا، ولا يمكن أن يحتوي إلا على سلاسل. وبما أنّها خاصة بعلامة التبويب، لا يمكن الوصول إليها من مشغّلي الويب أو مشغّلي الخدمات.
يجب تجنُّب استخدام LocalStorage لأنّه متزامن وسيؤدي إلى حظر سلسلة التعليمات الرئيسية. يقتصر حجمها على 5 ميغابايت تقريبًا ويمكن أن تحتوي على سلاسل فقط. لا يمكن الوصول إلى LocalStorage من مشغّلي الويب أو مشغّلي الخدمات.
ملفات تعريف الارتباط لها استخداماتها، ولكن لا يجب استخدامها للتخزين. يتم إرسال ملفات تعريف الارتباط مع كل طلب HTTP، لذا سيؤدي تخزين أي شيء أكبر من كمية صغيرة من البيانات إلى زيادة حجم كل طلب ويب بشكل كبير. وهي متزامنة ولا يمكن الوصول إليها من عاملي الويب. مثل LocalStorage وSessionStorage، تقتصر ملفات تعريف الارتباط على السلاسل فقط.
تم تصميم واجهة برمجة التطبيقات File System Access API لتتيح للمستخدمين قراءة الملفات وتعديلها على نظام الملفات المحلي. يجب أن يمنح المستخدم الإذن قبل أن تتمكّن الصفحة من قراءة أي ملف محلي أو الكتابة فيه، ولا يتم الاحتفاظ بالأذونات بين الجلسات، ما لم يتم تخزين معرّف الملف مؤقتًا في IndexedDB. تكون File System Access API الأنسب لحالات الاستخدام، مثل أدوات التحرير، حيث تحتاج إلى فتح ملف وتعديله ثم حفظ التغييرات في الملف.
توفّر واجهة File System API وواجهة FileWriter API طرقًا لقراءة الملفات وكتابتها في نظام ملفات معزول. على الرغم من أنّها غير متزامنة، لا ننصح باستخدامها لأنّها تتوفّر فقط في المتصفّحات المستنِدة إلى Chromium.
ما هو حجم البيانات التي يمكنني تخزينها؟
باختصار، الكثير، أي ما لا يقل عن بضع مئات من الميغابايت، وربما مئات الغيغابايت أو أكثر. تختلف عمليات التنفيذ في المتصفّح، ولكن يعتمد مقدار مساحة التخزين المتاحة عادةً على مقدار مساحة التخزين المتوفّرة على الجهاز.
- يسمح Chrome للمتصفّح باستخدام ما يصل إلى% 80 من إجمالي مساحة القرص. يمكن أن يستخدم المصدر ما يصل إلى% 60 من إجمالي مساحة القرص. يمكنك استخدام StorageManager
API لتحديد الحد الأقصى للحصة المتاحة. قد تختلف المتصفحات الأخرى المستندة إلى Chromium.
- في "وضع التصفّح المتخفي"، يقلّل Chrome مقدار مساحة التخزين التي يمكن أن يستخدمها مصدر معيّن إلى% 5 تقريبًا من إجمالي مساحة القرص.
- إذا فعّل المستخدم الخيار "محو بيانات الموقع الإلكتروني وملفات تعريف الارتباط عند إغلاق جميع النوافذ" في Chrome، سيتم تقليل مساحة التخزين المتوفّرة بشكل كبير إلى 300 ميغابايت كحد أقصى تقريبًا.
- يسمح Firefox للمتصفّح باستخدام ما يصل إلى% 50 من مساحة القرص الخالية. يمكن لمجموعة eTLD+1 (مثل
example.comوwww.example.comوfoo.bar.example.com) استخدام ما يصل إلى 2 غيغابايت. يمكنك استخدام StorageManager API لتحديد مقدار المساحة المتبقية. - يبدو أنّ متصفّح Safari (على كلّ من أجهزة الكمبيوتر والأجهزة الجوّالة) يسمح بحوالي 1 غيغابايت. عند بلوغ الحد الأقصى، سيطلب Safari من المستخدم زيادة الحد بمقدار 200 ميغابايت. لم أتمكّن من العثور على أي مستندات رسمية حول هذا الموضوع.
- إذا تمت إضافة تطبيق ويب تقدّمي إلى الشاشة الرئيسية على متصفّح Safari للأجهزة الجوّالة، سيتم إنشاء حاوية تخزين جديدة، ولن تتم مشاركة أي بيانات بين تطبيق الويب التقدّمي ومتصفّح Safari للأجهزة الجوّالة. بعد استنفاد الحصة المخصّصة لتطبيق ويب تقدّمي مثبَّت، لا يبدو أنّ هناك أي طريقة لطلب مساحة تخزين إضافية.
في السابق، إذا تجاوز موقع إلكتروني حدًا معيّنًا من البيانات المخزّنة، كان المتصفّح يطلب من المستخدم منح الإذن باستخدام المزيد من البيانات. على سبيل المثال، إذا كان المصدر يستخدم أكثر من 50 ميغابايت، سيطلب المتصفّح من المستخدم السماح له بتخزين ما يصل إلى 100 ميغابايت، ثم يطلب منه ذلك مرة أخرى عند زيادات قدرها 50 ميغابايت.
في الوقت الحالي، لا تطلب معظم المتصفّحات الحديثة من المستخدم الإذن، بل تسمح للموقع الإلكتروني باستخدام ما يصل إلى حصته المخصّصة. يبدو أنّ Safari هو الاستثناء الوحيد، إذ يعرض رسالة طلب عند تجاوز مساحة التخزين المتوفّرة، ويطلب الإذن بزيادة الحصة المخصّصة. إذا حاول مصدر استخدام حصة أكبر من الحصة المخصّصة له، ستفشل المحاولات اللاحقة لكتابة البيانات.
كيف يمكنني التحقّق من حجم مساحة التخزين المتوفّرة؟
في العديد من المتصفّحات، يمكنك استخدام StorageManager API لتحديد مقدار مساحة التخزين المتاحة للمصدر ومقدار مساحة التخزين التي يستخدمها. تعرض هذه السمة إجمالي عدد وحدات البايت المستخدَمة من خلال IndexedDB وCache API، وتتيح إمكانية احتساب مساحة التخزين المتبقية التقريبية المتاحة.
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate();
// quota.usage -> Number of bytes used.
// quota.quota -> Maximum number of bytes available.
const percentageUsed = (quota.usage / quota.quota) * 100;
console.log(`You've used ${percentageUsed}% of the available storage.`);
const remaining = quota.quota - quota.usage;
console.log(`You can write up to ${remaining} more bytes.`);
}
يجب رصد الأخطاء المتعلقة بتجاوز الحصة (راجِع أدناه). في بعض الحالات، قد يتجاوز الحصص المتاحة مقدار مساحة التخزين المتوفرة.
فحص
أثناء عملية التطوير، يمكنك استخدام "أدوات مطوري البرامج" في المتصفّح لفحص أنواع التخزين المختلفة ومحو جميع البيانات المخزّنة.
تمت إضافة ميزة جديدة في الإصدار 88 من Chrome تتيح لك تجاهل حصة التخزين المحدّدة للموقع الإلكتروني في "لوحة التخزين". تمنحك هذه الميزة إمكانية محاكاة أجهزة مختلفة واختبار سلوك تطبيقاتك في سيناريوهات انخفاض مساحة التخزين المتاحة على القرص. انتقِل إلى التطبيق ثم مساحة التخزين، وفعِّل مربّع الاختيار محاكاة مساحة التخزين المخصّصة والمتوفرة، وأدخِل أي رقم صالح لمحاكاة مساحة التخزين المتوفرة.
أثناء العمل على هذا الدليل، كتبت أداة بسيطة لمحاولة استخدام أكبر قدر ممكن من مساحة التخزين بسرعة. وهي طريقة سريعة لتجربة آليات تخزين مختلفة ومعرفة ما يحدث عند استخدام كل حصتك.
كيفية التعامل مع تجاوز الحصة
ماذا يجب أن تفعل عند تجاوز الحصة؟ والأهم من ذلك، يجب دائمًا رصد أخطاء الكتابة ومعالجتها، سواء كانت QuotaExceededError أو غير ذلك. بعد ذلك، حدِّد كيفية التعامل معها استنادًا إلى تصميم تطبيقك.
على سبيل المثال، يمكنك حذف المحتوى الذي لم يتم الوصول إليه منذ فترة طويلة، أو إزالة البيانات استنادًا إلى حجمها، أو توفير طريقة للمستخدمين لاختيار ما يريدون حذفه.
تعرض كلّ من IndexedDB وCache API الخطأ DOMError الذي يحمل الاسم
QuotaExceededError عند تجاوز الحصة المتاحة.
IndexedDB
إذا تجاوز المصدر حصته، ستفشل محاولات الكتابة إلى IndexedDB. سيتم استدعاء معالج onabort() للمعاملة، مع تمرير حدث.
سيتضمّن الحدث DOMException في سمة الخطأ. سيؤدي التحقّق من الخطأ name إلى عرض QuotaExceededError.
const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
const error = event.target.error; // DOMException
if (error.name == 'QuotaExceededError') {
// Fallback code goes here
}
};
واجهة برمجة تطبيقات Cache
إذا تجاوز المصدر حصته، سيتم رفض محاولات الكتابة إلى Cache API مع ظهور الخطأ QuotaExceededError DOMException.
try {
const cache = await caches.open('my-cache');
await cache.add(new Request('/sample1.jpg'));
} catch (err) {
if (error.name === 'QuotaExceededError') {
// Fallback code goes here
}
}
كيف تتم عملية الإخلاء؟
يتم تصنيف مساحة التخزين على الويب إلى فئتَين، هما "أفضل جهد" و "مستمرة". يشير مصطلح "أفضل جهد" إلى أنّه يمكن للمتصفّح محو مساحة التخزين بدون مقاطعة المستخدم، ولكنّها أقل متانة للبيانات المهمة أو طويلة الأمد. لا تتم إزالة البيانات المخزّنة بشكل دائم تلقائيًا عندما تكون مساحة التخزين منخفضة. على المستخدم محو مساحة التخزين هذه يدويًا (من خلال إعدادات المتصفّح).
بشكلٍ تلقائي، تندرج بيانات الموقع الإلكتروني (بما في ذلك IndexedDB وCache API وما إلى ذلك) ضمن فئة "أفضل جهد"، ما يعني أنّه ما لم يطلب الموقع الإلكتروني تخزينًا دائمًا، يمكن للمتصفّح إزالة بيانات الموقع الإلكتروني حسب تقديره، مثلاً عندما تكون مساحة التخزين على الجهاز منخفضة.
سياسة الإخلاء في وضع "أفضل جهد" هي:
- ستبدأ المتصفّحات المستندة إلى Chromium في إزالة البيانات عندما ينفد مساحة التخزين في المتصفّح، وسيتم محو جميع بيانات المواقع الإلكترونية بدءًا من المصدر الأقل استخدامًا مؤخرًا، ثم المصدر التالي، إلى أن يتوقف المتصفّح عن تجاوز الحدّ الأقصى.
- سيبدأ Firefox في إخلاء البيانات عندما تمتلئ مساحة القرص المتوفرة، وذلك عن طريق محو جميع بيانات الموقع الإلكتروني من المصدر الأقل استخدامًا أولاً، ثم المصدر التالي، إلى أن يتوقف المتصفح عن تجاوز الحد.
- لم يكن Safari يحذف البيانات في السابق، ولكنّه فرض مؤخرًا حدًا أقصى جديدًا يبلغ سبعة أيام على جميع مساحات التخزين القابلة للكتابة (راجِع ما يلي).
بدءًا من الإصدار 13.4 من iOS وiPadOS والإصدار 13.1 من Safari على macOS، سيتم فرض حد أقصى لمدة سبعة أيام على جميع مساحات التخزين التي يمكن كتابة النصوص البرمجية فيها، بما في ذلك IndexedDB وتسجيل عامل الخدمة وCache API. وهذا يعني أنّ Safari سيزيل كل المحتوى من ذاكرة التخزين المؤقت بعد سبعة أيام من استخدام Safari إذا لم يتفاعل المستخدم مع الموقع الإلكتروني. لا تنطبق سياسة الإزالة هذه على تطبيقات الويب التقدّمية المثبّتة التي تمت إضافتها إلى الشاشة الرئيسية. يمكنك الاطّلاع على الحظر الكامل لملفات تعريف الارتباط التابعة لجهات خارجية والمزيد على مدونة WebKit للحصول على التفاصيل الكاملة.
حِزم التخزين
تتمثّل الفكرة الأساسية لواجهة برمجة التطبيقات Storage Buckets API في منح المواقع الإلكترونية القدرة على إنشاء حِزم تخزين متعددة، حيث يمكن للمتصفّح اختيار حذف كل حزمة بشكل مستقل عن الحِزم الأخرى. ويتيح ذلك للمطوّرين تحديد أولويات الإخلاء لضمان عدم حذف البيانات الأكثر أهمية.
ميزة إضافية: لماذا يجب استخدام برنامج تضمين IndexedDB؟
IndexedDB هي واجهة برمجة تطبيقات منخفضة المستوى تتطلّب إعدادًا كبيرًا قبل الاستخدام، ما قد يكون مزعجًا بشكل خاص عند تخزين بيانات منخفضة التعقيد. وعلى عكس معظم واجهات برمجة التطبيقات الحديثة المستندة إلى الوعود، تستند هذه الواجهة إلى الأحداث. تخفي أدوات تضمين الوعود، مثل idb لـ IndexedDB، بعض الميزات الفعّالة، والأهم من ذلك، تخفي الآلية المعقّدة (مثل المعاملات وإصدار المخطط) التي تأتي مع مكتبة IndexedDB.
ميزة إضافية: SQLite Wasm
بعد إيقاف لغة الاستعلامات البنيوية (SQL) على الويب نهائيًا وإزالتها من Chrome، تعاونت Google مع المسؤولين عن صيانة قاعدة بيانات SQLite الشائعة لتوفير بديل للغة الاستعلامات البنيوية (SQL) على الويب استنادًا إلى SQLite. يمكنك الاطّلاع على SQLite Wasm في المتصفّح الذي يستند إلى نظام الملفات الخاص بالمصدر للحصول على تفاصيل حول كيفية استخدامه.
الخاتمة
انتهت أيام مساحة التخزين المحدودة ومطالبة المستخدم بتخزين المزيد والمزيد من البيانات. يمكن للمواقع الإلكترونية تخزين جميع الموارد والبيانات التي تحتاج إليها لتشغيلها. باستخدام StorageManager API، يمكنك تحديد مقدار المساحة المتوفّرة لك والمساحة التي استخدمتها. باستخدام التخزين الدائم، يمكنك حماية البيانات من الإزالة ما لم يزِلها المستخدم.
مراجع إضافية
شكرًا
نشكر كلّ من "جاريد غودمان" و"فيل والتون" و"إيجي كيتامورا" و"دانيال مورفي" و"داروين هوانغ" و"جوش بيل" و"مارين كرويسيلبرينك" و"فيكتور كوستان" على مراجعة هذا الدليل. نشكر "إيجي كيتامورا" و"آدي عثماني" و"مارك كوهين" الذين كتبوا المقالات الأصلية التي تستند إليها هذه المقالة. كتب إيجي أداة مفيدة اسمها Browser Storage Abuser، وقد كانت مفيدة في التحقّق من صحة السلوك الحالي. يتيح لك ذلك تخزين أكبر قدر ممكن من البيانات والاطّلاع على حدود مساحة التخزين في المتصفّح. نشكر "فرانسوا بوفورت" على البحث المعمّق في Safari لمعرفة حدود مساحة التخزين، و"توماس شتاينر" على إضافة معلومات حول نظام الملفات الخاص بالمصدر، وحِزم التخزين، وSQLite Wasm، وتعديل المحتوى بشكل عام في عام 2024.