مقدمة
تزداد أهمية إمكانية استخدام التطبيقات المستندة إلى الويب بلا اتصال بالإنترنت. نعم، يمكن لجميع المتصفّحات تخزين الصفحات والموارد مؤقتًا لفترات طويلة إذا تمّت مطالبتها بذلك، ولكن يمكن للمتصفّح إزالة عناصر فردية من ذاكرة التخزين المؤقت في أي وقت لإفساح المجال لعناصر أخرى. يعالج HTML5 بعض المشاكل المزعجة التي تواجهك عند عدم الاتصال بالإنترنت باستخدام واجهة ApplicationCache. يوفّر استخدام واجهة ذاكرة التخزين المؤقت لتطبيقك ثلاث مزايا:
- التصفّح بلا إنترنت: يمكن للمستخدمين التنقّل في موقعك الإلكتروني بالكامل عندما يكونون بلا إنترنت.
- السرعة: يتم الحصول على الموارد مباشرةً من القرص، بدون الحاجة إلى الاتصال بالشبكة.
- المرونة: إذا تعطّل موقعك الإلكتروني بسبب "الصيانة" (مثلاً، إذا تعطّل كل شيء عن طريق الخطأ)، سيحصل المستخدمون على تجربة بلا إنترنت.
تسمح ذاكرة التخزين المؤقت للتطبيقات (أو AppCache) للمطوّر بتحديد الملفات التي يجب أن يخزنها المتصفّح في ذاكرة التخزين المؤقت ويُتاحها للمستخدمين بلا اتصال بالإنترنت. سيتم تحميل تطبيقك ويعمل بشكل صحيح، حتى إذا ضغط المستخدم على زر إعادة التحميل أثناء عدم الاتصال بالإنترنت.
ملف بيان ذاكرة التخزين المؤقت
ملف بيان ذاكرة التخزين المؤقت هو ملف نصي بسيط يسرد الموارد التي يجب أن يخزنها المتصفّح في ذاكرة التخزين المؤقت للوصول إليها بلا اتصال بالإنترنت.
الإشارة إلى ملف بيان
لتفعيل ذاكرة التخزين المؤقت للتطبيق، أدرِج سمة البيان في علامة html
في
الملف:
<html manifest="example.appcache">
...
</html>
يجب تضمين سمة manifest
في كل صفحة من صفحات تطبيق الويب
التي تريد تخزينها مؤقتًا. لا يخزّن المتصفّح أي صفحة في ذاكرة التخزين المؤقت إذا لم تكن تحتوي على سمة manifest
(ما لم يتم إدراجها صراحةً في ملف البيان نفسه). وهذا يعني أنّ أي صفحة ينتقل إليها المستخدم والتي
تتضمّن manifest
ستتم إضافتها ضمنيًا إلى ذاكرة التخزين المؤقت للتطبيق.
وبالتالي، ليس عليك إدراج كل صفحة في البيان. إذا كانت الصفحة تشير إلى بيان، لا تتوفّر طريقة لمنع تخزين هذه الصفحة مؤقتًا.
يمكنك الاطّلاع على عناوين URL التي تتحكّم فيها ذاكرة التخزين المؤقت للتطبيق من خلال الانتقال إلى about://://appcache-internals/ في Chrome. من هنا، يمكنك محو ذاكرات التخزين المؤقت وعرض الإدخالات. تتوفّر أدوات مطوّرين مشابهة في Firefox.
يمكن أن تشير السمة manifest
إلى عنوان URL مطلق أو مسار نسبي،
ولكن يجب أن يكون عنوان URL المطلق ضمن المصدر نفسه لتطبيق الويب.
يمكن أن يحتوي ملف البيان على أي امتداد ملف، ولكن يجب عرضه
باستخدام نوع mime الصحيح (راجِع المعلومات أدناه).
<html manifest="http://www.example.com/example.mf">
...
</html>
يجب عرض ملف البيان باستخدام نوع mime text/cache-manifest
.
قد تحتاج إلى إضافة نوع ملف مخصّص إلى خادم الويب أو إعدادات .htaccess
.
على سبيل المثال، لعرض نوع mime هذا في Apache، أضِف هذا السطر إلى ملف الإعدادات:
AddType text/cache-manifest .appcache
أو في ملف app.yaml في Google App Engine:
- url: /mystaticdir/(.*\.appcache)
static_files: mystaticdir/\1
mime_type: text/cache-manifest
upload: mystaticdir/(.*\.appcache)
تمّ إسقاط هذا الشرط من المواصفات منذ بعض الوقت، ولم يعُد مطلوبًا في أحدث إصدارات Chrome وSafari وFirefox، ولكنّك ستحتاج إلى mime-type لكي تعمل في المتصفّحات القديمة وInternet Explorer 11.
بنية ملف البيان
البيان هو ملف منفصل تربطه من خلال سمة البيان في عنصر html. يظهر البيان البسيط على النحو التالي:
CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js
سيخزّن هذا المثال أربعة ملفات في ذاكرة التخزين المؤقت على الصفحة التي تحدّد ملف البيان هذا.
في ما يلي بعض النقاط التي يجب أخذها في الاعتبار:
- سلسلة
CACHE MANIFEST
هي السطر الأول وهي مطلوبة. - يمكن أن تكون الملفات من نطاق آخر
- تفرض بعض المتصفّحات قيودًا على مقدار مساحة التخزين المتاحة
لتطبيقك. في Chrome مثلاً، يستخدم AppCache مجموعة مشتركة من مساحة التخزين المؤقتة
التي يمكن أن تشاركها واجهات برمجة التطبيقات الأخرى التي تعمل بلا إنترنت. إذا كنت تكتب تطبيقًا لـ سوق Chrome الإلكتروني، يزيل استخدام الرمز
unlimitedStorage
هذا القيد. - إذا كان البيان نفسه يعرض الخطأ 404 أو 410، يتم حذف ذاكرة التخزين المؤقت.
- إذا تعذّر تنزيل البيان أو أحد الموارد المحدّدة فيه، تتعذّر عملية تعديل ذاكرة التخزين المؤقت بالكامل. سيواصل المتصفّح استخدام ملف التخزين المؤقّت القديم للتطبيق في حال تعذّر تحميل البيانات.
لنلقِ نظرة على مثال أكثر تعقيدًا:
CACHE MANIFEST
# 2010-06-18:v2
# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js
# Resources that require the user to be online.
NETWORK:
*
# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
الأسطر التي تبدأ بعلامة "#" هي أسطر تعليقات، ولكن يمكن أن تخدم أيضًا غرضًا آخر. لا يتم تعديل ذاكرة التخزين المؤقت للتطبيق إلا عند تغيير ملف البيان الخاص به. على سبيل المثال، إذا عدّلت مرجع صورة أو غيّرت دالة JavaScript، لن تتم مجددًا تخزين هذه التغييرات مؤقتًا. يجب تعديل ملف البيان نفسه لإعلام المتصفّح بإعادة تحميل الملفات المخزّنة مؤقتًا.
تجنَّب استخدام طابع زمني يتم تعديله باستمرار أو سلسلة عشوائية لفرض التحديثات في كل مرة. يتم التحقّق من البيان مرّتين أثناء التحديث، مرّة في البداية ومرّة بعد تعديل جميع الملفات المخزّنة مؤقتًا. إذا تغيّر البيان أثناء التحديث، من المحتمل أن يكون المتصفّح قد جلب بعض الملفات من إصدار معيّن وملفات أخرى من إصدار آخر، لذا لا يطبّق ذاكرة التخزين المؤقت ويعيد المحاولة لاحقًا.
على الرغم من أنّ ذاكرة التخزين المؤقت يتم تعديلها، لن يستخدم المتصفّح هذه الملفات إلى أن تتم إعادة تحميل الصفحة، لأنّ التعديلات تحدث بعد تحميل الصفحة من الإصدار الحالي من ذاكرة التخزين المؤقت.
يمكن أن يتضمّن البيان ثلاثة أقسام متميزة: CACHE
وNETWORK
وFALLBACK
.
CACHE:
- هذا هو القسم التلقائي للإدخالات. سيتم تخزين الملفات المدرَجة ضمن هذا العنوان (أو بعد الرمز
CACHE MANIFEST
مباشرةً) بشكل صريح في الذاكرة المؤقتة بعد تنزيلها للمرة الأولى.NETWORK:
- قد تأتي الملفات المدرَجة في هذا القسم من الشبكة إذا لم تكن متوفّرة في ذاكرة التخزين المؤقت، وإلا لن يتم استخدام الشبكة حتى إذا كان المستخدم متصلاً بالإنترنت. يمكنك إدراج عناوين URL معيّنة في القائمة المسموح بها هنا، أو يمكنك ببساطة استخدام "" للسماح بجميع عناوين URL. تحتاج معظم المواقع الإلكترونية إلى "".
FALLBACK:
- قسم اختياري يحدّد الصفحات الاحتياطية في حال تعذّر الوصول إلى أحد الموارد معرّف URI الأول هو المورد، والثاني هو العنصر الاحتياطي المستخدَم في حال تعذّر طلب الشبكة أو حدوث أخطاء. يجب أن يكون كلا معرّفَي الموارد المنتظمَين من المصدر نفسه لملف البيان. يمكنك تسجيل عناوين URL محدّدة، بالإضافة إلى بادئات عناوين URL. سيسجّل "images/large/" حالات الفشل من عناوين URL مثل "images/large/whatever/img.jpg".
يحدِّد البيان التالي صفحة "صيدة خاطئة" (offline.html) التي سيتم عرضها عندما يحاول المستخدِم الوصول إلى جذر الموقع الإلكتروني عندما يكون غير متصل بالإنترنت. ويُشير أيضًا إلى أنّ جميع الموارد الأخرى (مثل تلك المتوفّرة على موقع إلكتروني عن بُعد) تتطلّب اتصالاً بالإنترنت.
CACHE MANIFEST
# 2010-06-18:v3
# Explicitly cached entries
index.html
css/style.css
# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html
# All other resources (e.g. sites) require the user to be online.
NETWORK:
*
# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png
تعديل ذاكرة التخزين المؤقت
بعد أن يصبح التطبيق غير متصل بالإنترنت، يظل محفوظًا مؤقتًا إلى أن يحدث أحد الإجراءَين التاليَين:
- يُمحو المستخدم مساحة تخزين بيانات موقعك الإلكتروني في المتصفّح.
- تم تعديل ملف البيان. ملاحظة: لا يعني تعديل ملف مُدرَج في البيان أنّ المتصفّح سيعيد تخزين هذا المورد مؤقتًا. يجب تغيير ملف البيان نفسه.
حالة ذاكرة التخزين المؤقت
عنصر window.applicationCache
هو إذن الوصول الآلي إلى ذاكرة التخزين المؤقت لتطبيقات المتصفّح.
يكون سمة status
مفيدة للتحقّق من الحالة الحالية لذاكرة التخزين المؤقت:
var appCache = window.applicationCache;
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY: // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};
للتحقّق آليًا من توفّر تحديثات للبيان، يجب أولاً استدعاء applicationCache.update()
.
سيؤدي ذلك إلى محاولة تعديل ذاكرة التخزين المؤقت للمستخدم (ما يتطلّب تغيير ملف البيان).
أخيرًا، عندما يكون applicationCache.status
في الحالة UPDATEREADY
، يؤديapplicationCache.swapCache()
إلى تبديل ذاكرة التخزين المؤقت القديمة بذاكرة التخزين المؤقت الجديدة.
var appCache = window.applicationCache;
appCache.update(); // Attempt to update the user's cache.
...
if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // The fetch was successful, swap in the new cache.
}
والخبر السار هو أنّه يمكنك إجراء ذلك تلقائيًا. لتعديل المستخدمين إلى
أحدث إصدار من موقعك الإلكتروني، اضبط مستمعًا لمراقبة حدث
updateready
عند تحميل الصفحة:
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
} else {
// Manifest didn't changed. Nothing new to server.
}
}, false);
}, false);
أحداث AppCache
كما هو متوقّع، يتم عرض أحداث إضافية لمراقبة حالة ذاكرة التخزين المؤقت. يُطلق المتصفّح أحداثًا لأمور مثل مستوى التقدّم في التنزيل وتعديل ذاكرة التخزين المؤقت للتطبيق وشروط الأخطاء. يُعدّ المقتطف التالي مستمعي الأحداث لكل نوع من أحداث ذاكرة التخزين المؤقت:
function handleCacheEvent(e) {
//...
}
function handleCacheError(e) {
alert('Error: Cache failed to update!');
};
// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);
// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);
// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);
// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);
// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);
// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);
// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);
// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);
إذا تعذّر تنزيل ملف البيان أو أحد الموارد المحدّدة فيه، تعذّر إجراء التحديث بالكامل. وسيواصل المتصفّح استخدام ذاكرة التخزين المؤقت القديمة للتطبيق في حال حدوث هذا الخطأ.
المراجع
- مواصفات واجهة برمجة التطبيقات ApplicationCache
- Application Cache هو أحمق: يتناول هذا المقال المشاكل المتعلقة بـ AppCache.