فضای ذخیره سازی برای وب

گزینه های مختلفی برای ذخیره داده ها در مرورگر وجود دارد. کدام یک برای نیازهای شما بهتر است؟

اتصالات اینترنتی ممکن است در حین حرکت ضعیف باشند یا وجود نداشته باشند، به همین دلیل است که پشتیبانی آفلاین و عملکرد قابل اعتماد از ویژگی های رایج در برنامه های وب پیشرفته هستند. حتی در محیط‌های بی‌سیم عالی، استفاده عاقلانه از حافظه پنهان و سایر تکنیک‌های ذخیره‌سازی می‌تواند تجربه کاربر را به میزان قابل توجهی بهبود بخشد. راه های مختلفی برای ذخیره منابع برنامه استاتیک (HTML، جاوا اسکریپت، CSS، تصاویر و غیره) و داده ها (داده های کاربر، مقالات خبری و غیره) وجود دارد. اما بهترین راه حل کدام است؟ چقدر می توانید ذخیره کنید؟ چگونه از اخراج آن جلوگیری می کنید؟

از چی استفاده کنم؟

در اینجا یک توصیه کلی برای ذخیره منابع آورده شده است:

IndexedDB، OPFS و Cache Storage API در هر مرورگر مدرن پشتیبانی می شود. آنها ناهمزمان هستند و رشته اصلی را مسدود نمی کنند (اما یک نوع همزمان از OPFS نیز وجود دارد که منحصراً در وب کارگران موجود است). آنها از طریق شی window ، وب کارگران و سرویسکاران قابل دسترسی هستند و استفاده از آنها را در هر جایی از کد شما ممکن می سازد.

در مورد سایر مکانیسم های ذخیره سازی چطور؟

چندین مکانیسم ذخیره‌سازی دیگر در مرورگر موجود است، اما استفاده محدودی از آنها وجود دارد و ممکن است مشکلات عملکردی قابل توجهی ایجاد کنند.

SessionStorage یک تب خاص است و به طول عمر برگه اختصاص دارد. ممکن است برای ذخیره مقادیر کمی از اطلاعات مربوط به جلسه، به عنوان مثال یک کلید IndexedDB مفید باشد. باید با احتیاط استفاده شود زیرا همزمان است و رشته اصلی را مسدود می کند. به حدود 5 مگابایت محدود شده است و فقط می تواند رشته ها را شامل شود. از آنجایی که مخصوص تب است، از وب‌کارگران یا سرویس‌دهندگان قابل دسترسی نیست.

LocalStorage باید اجتناب شود زیرا همزمان است و رشته اصلی را مسدود می کند. به حدود 5 مگابایت محدود شده است و فقط می تواند رشته ها را شامل شود. LocalStorage از وب‌کارگران یا کارکنان خدمات قابل دسترسی نیست.

کوکی ها کاربردهای خود را دارند، اما نباید برای ذخیره سازی استفاده شوند. کوکی ها با هر درخواست HTTP ارسال می شوند، بنابراین ذخیره هر چیزی بیش از مقدار کمی داده، اندازه هر درخواست وب را به میزان قابل توجهی افزایش می دهد. آنها همزمان هستند و از وب سایت ها قابل دسترسی نیستند. مانند LocalStorage و SessionStorage، کوکی ها فقط به رشته ها محدود می شوند.

File System Access API طراحی شده است تا کاربران بتوانند فایل‌ها را در سیستم فایل محلی خود بخوانند و ویرایش کنند. کاربر باید قبل از اینکه یک صفحه بتواند در هر فایل محلی بخواند یا بنویسد مجوز بدهد، و مجوزها در تمام جلسات باقی نمی مانند، مگر اینکه یک دسته فایل در IndexedDB ذخیره شود. File System Access API برای موارد استفاده مانند ویرایشگرها مناسب است، جایی که باید یک فایل را باز کنید، آن را تغییر دهید و سپس احتمالاً تغییرات را در فایل ذخیره کنید.

File System API و FileWriter API روش هایی را برای خواندن و نوشتن فایل ها در یک سیستم فایل سندباکس ارائه می کنند. در حالی که ناهمزمان است، توصیه نمی شود زیرا فقط در مرورگرهای مبتنی بر Chromium در دسترس است.

چقدر می توانم ذخیره کنم؟

به طور خلاصه، مقدار زیادی ، حداقل چند صد مگابایت، و به طور بالقوه صدها گیگابایت یا بیشتر. پیاده سازی مرورگرها متفاوت است، اما میزان فضای ذخیره سازی موجود معمولاً بر اساس میزان فضای ذخیره سازی موجود در دستگاه است.

  • کروم به مرورگر اجازه می دهد تا 80 درصد از کل فضای دیسک را استفاده کند. یک مبدا می تواند تا 60 درصد از کل فضای دیسک را استفاده کند. می توانید از StorageManager API برای تعیین حداکثر سهمیه موجود استفاده کنید. سایر مرورگرهای مبتنی بر Chromium ممکن است متفاوت باشند.
    • در حالت ناشناس، Chrome مقدار فضای ذخیره‌سازی را که یک منبع می‌تواند استفاده کند به تقریباً 5 درصد از کل فضای دیسک کاهش می‌دهد.
    • اگر کاربر «پاک کردن کوکی‌ها و داده‌های سایت هنگام بستن همه پنجره‌ها» را در Chrome فعال کرده باشد، سهمیه فضای ذخیره‌سازی به میزان قابل توجهی به حداکثر تقریباً 300 مگابایت کاهش می‌یابد.
  • فایرفاکس به مرورگر اجازه می دهد تا 50 درصد از فضای خالی دیسک را استفاده کند. یک گروه eTLD+1 (به عنوان مثال، example.com ، www.example.com و foo.bar.example.com ) ممکن است تا 2 گیگابایت استفاده کند . می‌توانید از StorageManager API برای تعیین میزان فضای موجود استفاده کنید.
  • به نظر می رسد سافاری (هم دسکتاپ و هم موبایل) حدود 1 گیگابایت اجازه می دهد. هنگامی که به حد مجاز رسید، سافاری از کاربر درخواست می کند و محدودیت را در 200 مگابایت افزایش می دهد. من نتوانستم هیچ سند رسمی در این مورد پیدا کنم.
    • اگر یک PWA به صفحه اصلی در سافاری موبایل اضافه شود، یک محفظه ذخیره‌سازی جدید ایجاد می‌کند و چیزی بین PWA و سافاری موبایل به اشتراک گذاشته نمی‌شود. هنگامی که سهمیه برای یک PWA نصب شده به دست آمد، به نظر نمی رسد راهی برای درخواست فضای ذخیره اضافی وجود داشته باشد.

در گذشته، اگر یک سایت از آستانه مشخصی از داده های ذخیره شده فراتر می رفت، مرورگر از کاربر می خواست که اجازه استفاده از داده های بیشتری را بدهد. به عنوان مثال، اگر منبع بیش از 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.`);
}

شما باید خطاهای بیش از سهمیه را بگیرید (به زیر مراجعه کنید). در برخی موارد، این امکان وجود دارد که سهمیه موجود بیش از مقدار واقعی فضای ذخیره‌سازی موجود باشد.

بازرسی کنید

در طول توسعه، می‌توانید از DevTools مرورگر خود برای بررسی انواع مختلف ذخیره‌سازی و پاک کردن تمام داده‌های ذخیره شده استفاده کنید.

ویژگی جدیدی در Chrome 88 اضافه شد که به شما امکان می‌دهد سهمیه فضای ذخیره‌سازی سایت را در قسمت Storage Pane لغو کنید. این ویژگی به شما این امکان را می دهد که دستگاه های مختلف را شبیه سازی کنید و رفتار برنامه های خود را در سناریوهای در دسترس بودن دیسک کم آزمایش کنید. به Application سپس Storage بروید، کادر بررسی Simulate custom storage quota را فعال کنید و هر عدد معتبری را برای شبیه سازی سهمیه ذخیره سازی وارد کنید.

در حین کار بر روی این راهنما، یک ابزار ساده نوشتم تا سعی کنم تا حد امکان به سرعت از فضای ذخیره سازی استفاده کنم. این یک راه سریع برای آزمایش مکانیسم‌های مختلف ذخیره‌سازی است و ببینید وقتی از تمام سهمیه خود استفاده می‌کنید چه اتفاقی می‌افتد.

چگونه می توان از سهمیه گذشت؟

وقتی از سهمیه عبور می کنید چه باید بکنید؟ مهمتر از همه، شما همیشه باید خطاهای نوشتن را، چه 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 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 زمانی که فضای مرورگر تمام شود شروع به حذف داده‌ها می‌کنند و ابتدا همه داده‌های سایت را از مبدأ که اخیراً استفاده شده است پاک می‌کنند، سپس بعدی را تا زمانی که مرورگر دیگر از حد مجاز خارج نشود.
  • وقتی فضای دیسک موجود پر شود، فایرفاکس شروع به حذف داده‌ها می‌کند، و ابتدا همه داده‌های سایت را از مبدأ کمتر استفاده شده پاک می‌کند، سپس بعدی را تا زمانی که مرورگر دیگر از حد مجاز خارج نشود.
  • Safari قبلاً داده‌ها را خارج نمی‌کرد، اما اخیراً یک سقف هفت روزه جدید را در تمام فضای ذخیره‌سازی قابل نوشتن پیاده‌سازی کرده است (به زیر مراجعه کنید).

با شروع iOS و iPadOS 13.4 و Safari 13.1 در macOS، محدودیت هفت روزه برای تمام فضای ذخیره‌سازی قابل نوشتن اسکریپت، از جمله IndexedDB، ثبت نام در سرویس‌کار، و Cache API وجود دارد. این بدان معناست که اگر کاربر با سایت تعامل نداشته باشد، سافاری پس از هفت روز استفاده از سافاری، تمام محتوا را از حافظه پنهان خارج می‌کند. این خط مشی اخراج برای PWA های نصب شده که به صفحه اصلی اضافه شده اند اعمال نمی شود . برای جزئیات کامل ، مسدود کردن کوکی‌های شخص ثالث و موارد دیگر را در وبلاگ WebKit ببینید.

سطل های ذخیره سازی

ایده اصلی Storage Buckets API این است که به سایت ها توانایی ایجاد سطل های ذخیره سازی متعدد را می دهد، جایی که مرورگر ممکن است انتخاب کند که هر سطل را مستقل از سایر سطل ها حذف کند. این به توسعه دهندگان اجازه می دهد تا اولویت بندی اخراج را مشخص کنند تا مطمئن شوند با ارزش ترین داده ها حذف نمی شوند.

امتیاز: چرا از یک پوشش برای IndexedDB استفاده کنید

IndexedDB یک API سطح پایین است که قبل از استفاده به تنظیمات قابل توجهی نیاز دارد، که می تواند به خصوص برای ذخیره داده های با پیچیدگی کم دردناک باشد. بر خلاف اکثر API های مبتنی بر وعده های مدرن، مبتنی بر رویداد است. بسته‌بندی‌های Promise مانند idb برای IndexedDB برخی از ویژگی‌های قدرتمند را پنهان می‌کنند، اما مهم‌تر از آن، ماشین‌های پیچیده (مانند تراکنش‌ها، نسخه‌سازی طرحواره) که با کتابخانه IndexedDB ارائه می‌شود را پنهان می‌کنند.

امتیاز: SQLite Wasm

پس از منسوخ شدن Web SQL و حذف از Chrome، Google با نگهبانان پایگاه داده محبوب SQLite همکاری کرد تا جایگزینی برای Web SQL بر اساس SQLite ارائه دهد. SQLite Wasm را در مرورگر تحت حمایت Origin Private File System برای جزئیات نحوه استفاده از آن بخوانید.

نتیجه گیری

دوران ذخیره سازی محدود و ترغیب کاربر به ذخیره اطلاعات بیشتر و بیشتر گذشته است. سایت ها می توانند به طور موثر تمام منابع و داده هایی را که برای اجرا نیاز دارند ذخیره کنند. با استفاده از StorageManager API می توانید تعیین کنید که چه مقدار در دسترس شما است و چه مقدار استفاده کرده اید. و با ذخیره سازی دائمی ، مگر اینکه کاربر آن را حذف کند، می توانید از آن در برابر تخلیه محافظت کنید.

منابع اضافی

با تشکر

تشکر ویژه از جرید گودمن، فیل والتون، ایجی کیتامورا، دانیل مورفی، داروین هوانگ، جاش بل، مارین کروسلبرینک و ویکتور کوستان برای بررسی این راهنما. با تشکر از ایجی کیتامورا، آدی عثمانی و مارک کوهن که مقالات اصلی را نوشتند که این بر اساس آن است. Eiji ابزار مفیدی به نام Browser Storage Abuser نوشت که در اعتبارسنجی رفتار فعلی مفید بود. این به شما امکان می دهد تا حد امکان داده ها را ذخیره کنید و محدودیت های ذخیره سازی را در مرورگر خود مشاهده کنید. از فرانسوا بوفورت که در Safari برای کشف محدودیت‌های ذخیره‌سازی آن تحقیق کرد و از توماس اشتاینر برای افزودن اطلاعاتی درباره سیستم فایل خصوصی مبدا، سطل‌های ذخیره‌سازی، SQLite Wasm و به‌روزرسانی کلی محتوا در سال ۲۰۲۴ تشکر می‌کنیم.

تصویر قهرمان توسط Guillaume Bolduc در Unsplash است.