هناك العديد من الخيارات المختلفة لتخزين البيانات في المتصفّح. أيّ منها هو الأنسب لاحتياجاتك؟
قد تكون اتصالات الإنترنت غير متّصلة أو غير متوفّرة أثناء التنقل، لذلك، إنّ إتاحة الاستخدام بلا إنترنت والأداء الموثوق به هما سمتان شائعتان في تطبيقات الويب المتقدّمة. حتى في البيئات اللاسلكية المثالية، يمكن أن يؤدي الاستخدام الحكيم لميزة التخزين المؤقت وتقنيات التخزين الأخرى إلى تحسين تجربة المستخدم بشكل كبير. هناك عدة طرق للاحتفاظ بنسخة مؤقتة من موارد تطبيقك الثابتة (HTML وJavaScript وCSS والصور وما إلى ذلك) و بياناته (بيانات المستخدمين والمقالات الإخبارية وما إلى ذلك). ولكن ما هو الحلّ الأفضل؟ كم يمكن تخزينه؟ كيف يمكنك منع إزالة المحتوى؟
ما الذي يجب استخدامه؟
في ما يلي اقتراح عام لتخزين الموارد:
- بالنسبة إلى موارد الشبكة اللازمة لتحميل تطبيقك، استخدِم Cache Storage API (جزء من خدمات العمال).
- بالنسبة إلى المحتوى المستنِد إلى الملفات، استخدِم نظام ملفات Origin Private File System (OPFS).
- بالنسبة إلى البيانات الأخرى، استخدِم IndexedDB (مع حزمة promises).
تتوفّر واجهتا برمجة التطبيقات IndexedDB وOPFS وCache Storage API في كل متصفّح حديث.
وهي غير متزامنة ولن تحظر سلسلة التعليمات الرئيسية (ولكن هناك أيضًا نوع متزامن
من OPFS متاح حصريًا في مهام الويب). ويمكن الوصول إليها
من عنصر 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
أو
أي شيء آخر. بعد ذلك، حدِّد كيفية التعامل مع هذه البيانات استنادًا إلى تصميم تطبيقك.
على سبيل المثال، يمكنك حذف المحتوى الذي لم يتم الوصول إليه منذ فترة طويلة، أو إزالة data استنادًا إلى الحجم، أو توفير طريقة للمستخدمين لاختيار ما يريدون حذفه.
يُعرِض كلّ من 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 API
إذا تجاوز المصدر حصته، سيتم رفض محاولات الكتابة إلى واجهة برمجة التطبيقات 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 يحذف البيانات في السابق، ولكن تم مؤخرًا تطبيق حدّ جديد لمدة سبعة أيام على كل مساحة التخزين القابلة للكتابة (راجِع المعلومات أدناه).
اعتبارًا من الإصدار iOS وiPadOS 13.4 وSafari 13.1 على نظام التشغيل macOS، تم وضع قيد يحدّد مدة الاحتفاظ بجميع مساحات التخزين القابلة للكتابة من خلال النصوص البرمجية، بما في ذلك IndexedDB وتسجيل worker service وCache API، وذلك لمدة سبعة أيام. يعني ذلك أنّ Safari سيزيل كل المحتوى من ذاكرة التخزين المؤقت بعد سبعة أيام من استخدام Safari إذا لم يتفاعل المستخدم مع الموقع الإلكتروني. لا تنطبق سياسة الاستبعاد هذه على التطبيقات المُثبَّتة المتوافقة مع الويب التي تمت إضافتها إلى الشاشة الرئيسية. اطّلِع على حظر ملفات تعريف الارتباط التابعة لجهات خارجية بالكامل وغير ذلك في مدوّنة WebKit للحصول على التفاصيل الكاملة.
حِزم التخزين
تتمثل الفكرة الأساسية لواجهة برمجة التطبيقات Storage Buckets API في منح المواقع الإلكترونية إمكانية إنشاء حِزم تخزين متعددة، حيث يمكن للمتصفّح اختيار حذف كل حزمة بشكل مستقل عن الحِزم الأخرى. يتيح ذلك للمطوّرين تحديد أولوية إزالة البيانات للتأكّد من عدم حذف البيانات الأكثر أهمية.
مكافأة: سبب استخدام حزمة برمجية لـ IndexedDB
IndexedDB هي واجهة برمجة تطبيقات من المستوى الأدنى تتطلّب إعدادًا مهمًا قبل الاستخدام، ما قد يكون مزعجًا بشكل خاص لتخزين البيانات منخفضة التعقيد. وعلى عكس معظم واجهات برمجة التطبيقات الحديثة التي تستند إلى الوعد، تستند هذه الواجهة إلى الأحداث. إنّ أدوات لفّ الوعد، مثل idb لـ IndexedDB، تحجب بعض الميزات القوية، ولكن الأهم من ذلك، أنها تحجب الآلية المعقدة (مثل المعاملات وإصدارات المخطط) التي تأتي مع مكتبة IndexedDB.
ميزة إضافية: SQLite Wasm
بعد إيقاف لغة الاستعلامات البنيوية (SQL) على الويب نهائيًا وإزالتها من Chrome، تعاونت Google مع القائمين على صيانة قاعدة بيانات SQLite الرائجة لتقديم بديل لـ Web SQL يستند إلى SQLite. اطّلِع على SQLite Wasm في المتصفّح المستند إلى نظام الملفات الخاص في Origin لمعرفة تفاصيل عن كيفية استخدامه.
الخاتمة
لقد ولت أيام مساحة التخزين المحدودة وطلب المستخدمين تخزين المزيد من البيانات. يمكن للمواقع الإلكترونية تخزين جميع الموارد والبيانات التي تحتاج إليها بفعالية. باستخدام واجهة برمجة التطبيقات StorageManager API، يمكنك معرفة المساحة المتوفّرة لك والمساحة التي استخدمتها. وباستخدام مساحة التخزين الثابتة، يمكنك حمايتها من الاستبعاد ما لم يزيلها المستخدم.
مراجع إضافية
- أفضل الممارسات المتعلّقة بـ IndexedDB
- مفاهيم مساحة التخزين على الويب ومساحة التخزين المتوفّرة في Chrome
شكرًا
نشكر بشكل خاص "جارييد غودمان" و"فيل والتون" و"إييجي كاتامورا" و"دانيال ميرفي" و"داروين هوانغ" و"جوش بيل" و"مارين كرويسلبرينك" و"فيكتور كوستان" على مراجعة هذا الدليل. نشكر "إيجي كيتامورا" و"أدي عثماني" و"مارك كوهين" الذين كتبوا المقالات الأصلية التي يستند إليها هذا المقال. كتب "إيجى" أداة مفيدة تُسمى Browser Storage Abuser، وكانت مفيدة في التحقّق من السلوك الحالي. يتيح لك هذا الإجراء تخزين أكبر قدر ممكن من البيانات والاطّلاع على حدود مساحة التخزين في المتصفّح. نشكر "فرانسوا بافورت" الذي أجرى البحث المتعمّق في Safari لمعرفة حدود مساحة التخزين، ونشكر "توماس شتاينر" على إضافة معلومات عن نظام الملفات الخاص الأصلي وحِزم التخزين وSQLite Wasm، بالإضافة إلى تعديل شامل على المحتوى في عام 2024.
الصورة الرئيسية من إنشاء Guillaume Bolduc على Unsplash.