من خلال برامج Service Workers، أتحنا للمطوّرين طريقة لحلّ مشاكل الاتصال بالشبكة. يمكنك التحكّم في التخزين المؤقت وطريقة معالجة الطلبات. وهذا يعني أنّه يمكنك إنشاء أنماطك الخاصة. اطّلِع على بعض الأنماط المحتملة بشكل منفصل، ولكن في الواقع، من المحتمل أن تستخدمها معًا، وذلك حسب عنوان URL والسياق.
للاطّلاع على عرض توضيحي لبعض هذه الأنماط، يمكنك الانتقال إلى Trained-to-thrill.
الحالات التي يجب فيها تخزين الموارد
تتيح لك مشغّلات الخدمات معالجة الطلبات بشكل مستقل عن التخزين المؤقت، لذا سأشرحها بشكل منفصل. أولاً، عليك تحديد الحالات التي يجب فيها استخدام ذاكرة التخزين المؤقت.
عند التثبيت، كحزمة تابعة
توفّر لك واجهة برمجة التطبيقات Service Worker API حدث install. يمكنك استخدام هذا الإجراء لتجهيز
بعض العناصر التي يجب أن تكون جاهزة قبل معالجة الأحداث الأخرى. أثناء
install، تستمر الإصدارات السابقة من مشغّل الخدمات في العمل وعرض الصفحات. يجب ألا يؤدي أي إجراء تتخذه في هذا الوقت إلى تعطيل عامل الخدمة الحالي.
مناسب للاستخدام مع: ملفات CSS أو الصور أو الخطوط أو JavaScript أو النماذج أو أي محتوى آخر تعتبره ثابتًا في هذا الإصدار من موقعك الإلكتروني.
استرجِع العناصر التي سيصبح موقعك الإلكتروني غير وظيفي تمامًا إذا تعذّر استرجاعها، وهي العناصر التي يضمّنها تطبيق مكافئ خاص بمنصة معيّنة في عملية التنزيل الأولية.
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open('mysite-static-v3').then(function (cache) {
return cache.addAll([
'/css/whatever-v3.css',
'/css/imgs/sprites-v6.png',
'/css/fonts/whatever-v8.woff',
'/js/all-min-v4.js',
// etc.
]);
}),
);
});
تتلقّى الدالة event.waitUntil وعدًا لتحديد مدة عملية التثبيت ونجاحها. إذا تم رفض الوعد، سيتم اعتبار عملية التثبيت فاشلة وسيتم إلغاء مشغّل الخدمات هذا (إذا كان إصدار أقدم قيد التشغيل، سيتم تركه بدون تغيير). caches.open() وcache.addAll() من الوعود المتعلقة بالإرجاع.
إذا تعذّر جلب أي من الموارد، سيتم رفض طلب الاتصال cache.addAll().
على trained-to-thrill، أستخدم هذه الميزة من أجل تخزين مواد العرض الثابتة مؤقتًا.
عند التثبيت، وليس كعنصر تابع
يشبه ذلك التثبيت كعنصر تابع، ولكن لن يؤدي إلى تأخير اكتمال عملية التثبيت ولن يتسبّب في تعذُّر التثبيت في حال تعذُّر التخزين المؤقت.
مناسب لـ: الموارد الأكبر حجمًا التي لا تحتاج إليها على الفور، مثل مواد العرض للمستويات اللاحقة من اللعبة.
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open('mygame-core-v1').then(function (cache) {
cache
.addAll
// levels 11-20
();
return cache
.addAll
// core assets and levels 1-10
();
}),
);
});
لا يمرّر هذا المثال وعد cache.addAll للمستويات من 11 إلى 20 إلى event.waitUntil، لذا حتى إذا تعذّر ذلك، ستظل اللعبة متاحة بلا إنترنت. بالطبع، عليك مراعاة إمكانية عدم توفّر هذه المستويات وإعادة محاولة تخزينها مؤقتًا إذا كانت غير متوفّرة.
قد يتم إيقاف عامل الخدمة أثناء تنزيل المستويات من 11 إلى 20 لأنّه انتهى من معالجة الأحداث، ما يعني أنّه لن يتم تخزينها مؤقتًا. يمكن لواجهة برمجة التطبيقات Web Periodic Background Synchronization API التعامل مع حالات مثل هذه، بالإضافة إلى عمليات التنزيل الأكبر حجمًا، مثل الأفلام.
عند التفعيل
مناسبة: للتنظيف ونقل البيانات
بعد تثبيت مشغّل خدمات جديد وعدم استخدام إصدار سابق، يتم تفعيل المشغّل الجديد، ويصلك حدث activate. وبما أنّ الإصدار السابق لم يعُد متاحًا، هذا هو الوقت المناسب للتعامل مع عمليات نقل المخطط في IndexedDB وحذف الذاكرات المؤقتة غير المستخدَمة.
self.addEventListener('activate', function (event) {
event.waitUntil(
caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames
.filter(function (cacheName) {
// Return true if you want to remove this cache,
// but remember that caches are shared across
// the whole origin
})
.map(function (cacheName) {
return caches.delete(cacheName);
}),
);
}),
);
});
أثناء التفعيل، يتم وضع أحداث مثل fetch في قائمة انتظار، وبالتالي قد يؤدي التفعيل الطويل إلى حظر عمليات تحميل الصفحات. يجب أن يكون التفعيل بسيطًا قدر الإمكان، ويجب استخدامه فقط للأشياء التي لا يمكنك تنفيذها أثناء تفعيل الإصدار السابق.
على trained-to-thrill، أستخدم هذا الخيار من أجل إزالة ذاكرات التخزين المؤقت القديمة.
عند تفاعل المستخدم
الحالات المناسبة: عندما يتعذّر إتاحة الموقع الإلكتروني بأكمله بلا إنترنت، وتختار السماح للمستخدم بتحديد المحتوى الذي يريد إتاحته بلا إنترنت. على سبيل المثال، فيديو على YouTube أو مقالة على Wikipedia أو معرض صور معيّن على Flickr
توفير زر "القراءة لاحقًا" أو "الحفظ للاطّلاع عليه بلا إنترنت" للمستخدم عند النقر عليه، يتم جلب ما تحتاج إليه من الشبكة وإضافته إلى ذاكرة التخزين المؤقت.
document.querySelector('.cache-article').addEventListener('click', function (event) {
event.preventDefault();
var id = this.dataset.articleId;
caches.open('mysite-article-' + id).then(function (cache) {
fetch('/get-article-urls?id=' + id)
.then(function (response) {
// /get-article-urls returns a JSON-encoded array of
// resource URLs that a given article depends on
return response.json();
})
.then(function (urls) {
cache.addAll(urls);
});
});
});
تتوفّر واجهة برمجة التطبيقات Cache API من الصفحات ومشغّلات الخدمات، ما يعني أنّه يمكنك إضافة محتوى إلى ذاكرة التخزين المؤقت مباشرةً من الصفحة.
عند تلقّي ردّ من الشبكة
مناسب للاستخدام في الحالات التالية: تعديل الموارد بشكل متكرر، مثل البريد الوارد للمستخدم أو محتوى المقالات وهي مفيدة أيضًا للمحتوى غير الأساسي، مثل صور الأفاتار، ولكن يجب توخّي الحذر.
إذا لم يتطابق الطلب مع أي شيء في ذاكرة التخزين المؤقت، يتم الحصول عليه من الشبكة وإرساله إلى الصفحة وإضافته إلى ذاكرة التخزين المؤقت في الوقت نفسه.
إذا نفّذت هذا الإجراء لمجموعة من عناوين URL، مثل الصور الرمزية، عليك الحرص على عدم زيادة حجم مساحة التخزين الخاصة بمصدرك. إذا كان المستخدم بحاجة إلى استعادة مساحة على القرص، لا تريد أن تكون المرشح الأول. احرص على التخلّص من العناصر غير الضرورية في ذاكرة التخزين المؤقت.
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open('mysite-dynamic').then(function (cache) {
return cache.match(event.request).then(function (response) {
return (
response ||
fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
})
);
});
}),
);
});
للسماح باستخدام الذاكرة بكفاءة، يمكنك قراءة نص الرد/الطلب مرة واحدة فقط. يستخدم نموذج الرمز .clone() لإنشاء نُسخ إضافية يمكن قراءتها بشكل منفصل.
على trained-to-thrill، أستخدم هذه الميزة من أجل تخزين صور Flickr مؤقتًا.
Stale-while-revalidate
مناسبة: للموارد التي يتم تعديلها بشكل متكرر والتي لا يكون من الضروري توفّر أحدث إصدار منها. يمكن أن تندرج الصور الرمزية ضمن هذه الفئة.
إذا كان هناك إصدار مخزّن مؤقتًا متاحًا، استخدِمه، ولكن احصل على تحديث لاستخدامه في المرة القادمة.
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open('mysite-dynamic').then(function (cache) {
return cache.match(event.request).then(function (response) {
var fetchPromise = fetch(event.request).then(function (networkResponse) {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return response || fetchPromise;
});
}),
);
});
يشبه هذا كثيرًا stale-while-revalidate في HTTP.
عند تلقّي رسالة فورية
Push API هي ميزة أخرى تستند إلى برنامج عامل الخدمة. يتيح ذلك تنشيط عامل الخدمة استجابةً لرسالة من خدمة المراسلة في نظام التشغيل. ويحدث ذلك حتى عندما لا تكون لدى المستخدم علامة تبويب مفتوحة لموقعك الإلكتروني. يتم تنبيه عامل الخدمة فقط. يمكنك طلب الإذن بذلك من إحدى الصفحات، وسيتم توجيه المستخدم إلى صفحة تطلب منه منح الإذن.
مناسب لـ: المحتوى المرتبط بإشعار، مثل رسالة دردشة أو خبر عاجل أو رسالة إلكترونية. المحتوى الذي لا يتغير كثيرًا والذي يستفيد من المزامنة الفورية، مثل تعديل قائمة المهام أو تغيير في التقويم
والنتيجة النهائية الشائعة هي إشعار يؤدي النقر عليه إلى فتح صفحة ذات صلة والتركيز عليها، ويُعدّ تعديل الذاكرات المؤقتة مسبقًا مهمًا للغاية في هذه الحالة. يكون المستخدم متصلاً بالإنترنت عند تلقّي الرسالة الإشعارية، ولكن قد لا يكون متصلاً عند تفاعله مع الإشعار، لذا من المهم إتاحة هذا المحتوى بلا اتصال بالإنترنت.
يعدّل هذا الرمز ذاكرات التخزين المؤقت قبل عرض الإشعار:
self.addEventListener('push', function (event) {
if (event.data.text() == 'new-email') {
event.waitUntil(
caches
.open('mysite-dynamic')
.then(function (cache) {
return fetch('/inbox.json').then(function (response) {
cache.put('/inbox.json', response.clone());
return response.json();
});
})
.then(function (emails) {
registration.showNotification('New email', {
body: 'From ' + emails[0].from.name,
tag: 'new-email',
});
}),
);
}
});
self.addEventListener('notificationclick', function (event) {
if (event.notification.tag == 'new-email') {
// Assume that all of the resources needed to render
// /inbox/ have previously been cached, e.g. as part
// of the install handler.
new WindowClient('/inbox/');
}
});
تفعيل المزامنة في الخلفية
مزامنة الخلفية هي ميزة أخرى تستند إلى Service Worker. تتيح لك هذه الطريقة طلب مزامنة البيانات في الخلفية لمرة واحدة أو على فترات (تجريبية للغاية). ويحدث ذلك حتى عندما لا يفتح المستخدم علامة تبويب لموقعك الإلكتروني. يتم تنشيط مشغّل الخدمات فقط. تطلب الإذن بذلك من صفحة، ويتم توجيه طلب إلى المستخدم.
مناسبة: للتحديثات غير العاجلة، خاصةً تلك التي تحدث بانتظام لدرجة أنّ إرسال رسالة دفع لكل تحديث سيكون متكررًا جدًا بالنسبة إلى المستخدمين، مثل الجداول الزمنية على وسائل التواصل الاجتماعي أو المقالات الإخبارية.
self.addEventListener('sync', function (event) {
if (event.id == 'update-leaderboard') {
event.waitUntil(
caches.open('mygame-dynamic').then(function (cache) {
return cache.add('/leaderboard.json');
}),
);
}
});
الاحتفاظ بذاكرة التخزين المؤقت
يتم منح المصدر مقدارًا معيّنًا من المساحة الخالية لاستخدامها كيفما يشاء. تتم مشاركة هذه المساحة المجانية بين جميع مساحات التخزين الخاصة بالمصدر، بما في ذلك مساحة التخزين(المحلية) وIndexedDB وFile System Access وذاكرات التخزين المؤقت.
المبلغ الذي ستحصل عليه غير محدّد. ويختلف ذلك حسب الجهاز وشروط التخزين. يمكنك معرفة المبلغ المتاح لك من خلال:
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.`);
}
ومع ذلك، كما هو الحال مع جميع مساحات التخزين في المتصفّح، يمكن للمتصفّح التخلّي عن بياناتك إذا كان الجهاز يعاني من ضغط في مساحة التخزين. لسوء الحظ، لا يمكن للمتصفّح التمييز بين الأفلام التي تريد الاحتفاظ بها بأي ثمن واللعبة التي لا تهمّك كثيرًا.
لحلّ هذه المشكلة، استخدِم واجهة StorageManager:
// From a page:
navigator.storage.persist()
.then(function(persisted) {
if (persisted) {
// Hurrah, your data is here to stay!
} else {
// So sad, your data may get chucked. Sorry.
});
بالطبع، على المستخدم منح الإذن. لإجراء ذلك، استخدِم Permissions API.
من المهم أن يكون المستخدم جزءًا من هذا المسار، لأنّه يمكننا الآن أن نتوقّع أن يكون لديه التحكّم في عملية الحذف. إذا كان جهاز المستخدم يعاني من ضغط على مساحة التخزين، ولم يؤدِّ محو البيانات غير الأساسية إلى حل المشكلة، يمكن للمستخدم تحديد العناصر التي يريد الاحتفاظ بها وإزالتها.
ولكي ينجح ذلك، يجب أن تتعامل أنظمة التشغيل مع المصادر "الدائمة" على أنّها مكافئة للتطبيقات الخاصة بالمنصة في تفاصيل استخدامها لمساحة التخزين، بدلاً من عرض المتصفّح كعنصر واحد.
اقتراحات العرض
وبغض النظر عن مقدار التخزين المؤقت الذي تجريه، لا يستخدم عامل الخدمة ذاكرة التخزين المؤقت إلا عندما تحدّد له متى وكيف. في ما يلي بعض الأنماط للتعامل مع الطلبات:
ذاكرة التخزين المؤقت فقط
مناسبة لما يلي: أي محتوى تعتبره ثابتًا في "نسخة" معيّنة من موقعك الإلكتروني. يجب أن تكون قد خزّنت هذه القيم مؤقتًا في حدث التثبيت، لذا يمكنك الاعتماد على توفّرها.
self.addEventListener('fetch', function (event) {
// If a match isn't found in the cache, the response
// will look like a connection error
event.respondWith(caches.match(event.request));
});
…على الرغم من أنّك لن تحتاج غالبًا إلى التعامل مع هذه الحالة تحديدًا، إلا أنّ التخزين المؤقت والرجوع إلى الشبكة يغطيانها.
الشبكة فقط
مناسب لـ: العناصر التي ليس لها مكافئ بلا إنترنت، مثل إشعارات الإحصاءات وطلبات غير GET.
self.addEventListener('fetch', function (event) {
event.respondWith(fetch(event.request));
// or don't call event.respondWith, which
// will result in default browser behavior
});
…على الرغم من أنّك لن تحتاج غالبًا إلى التعامل مع هذه الحالة تحديدًا، فإنّ التخزين المؤقت والرجوع إلى الشبكة يغطيانها.
ذاكرة التخزين المؤقت، مع الرجوع إلى الشبكة
مناسبة: لإنشاء تطبيقات تعمل في وضع عدم الاتصال بالإنترنت. في مثل هذه الحالات، إليك الطريقة التي ستتعامل بها مع معظم الطلبات. تُعدّ الأنماط الأخرى استثناءات استنادًا إلى الطلب الوارد.
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
return response || fetch(event.request);
}),
);
});
يمنحك ذلك سلوك "ذاكرة التخزين المؤقت فقط" للعناصر الموجودة في ذاكرة التخزين المؤقت وسلوك "الشبكة فقط" لأي عناصر غير مخزّنة مؤقتًا (بما في ذلك جميع طلبات HTTP غير GET، لأنّه لا يمكن تخزينها مؤقتًا).
تضارب بين ذاكرة التخزين المؤقت والشبكة
مثالية: للأصول الصغيرة التي تسعى إلى تحقيق أداء جيد على الأجهزة التي يكون الوصول إلى القرص فيها بطيئًا.
مع بعض المجموعات من محركات الأقراص الثابتة القديمة وبرامج فحص الفيروسات واتصالات الإنترنت الأسرع، يمكن أن يكون الحصول على الموارد من الشبكة أسرع من الوصول إلى القرص. ومع ذلك، قد يؤدي الانتقال إلى الشبكة عندما يتوفّر المحتوى على جهاز المستخدم إلى استهلاك البيانات بلا داعٍ، لذا يجب مراعاة ذلك.
// Promise.race rejects when a promise rejects before fulfilling.
// To make a race function:
function promiseAny(promises) {
return new Promise((resolve, reject) => {
// make sure promises are all promises
promises = promises.map((p) => Promise.resolve(p));
// resolve this promise as soon as one resolves
promises.forEach((p) => p.then(resolve));
// reject if all promises reject
promises.reduce((a, b) => a.catch(() => b)).catch(() => reject(Error('All failed')));
});
}
self.addEventListener('fetch', function (event) {
event.respondWith(promiseAny([caches.match(event.request), fetch(event.request)]));
});
الشبكة تعود إلى ذاكرة التخزين المؤقت
مناسبة للحالات التالية: حلّ سريع للموارد التي يتم تعديلها بشكل متكرر، خارج "إصدار" الموقع الإلكتروني على سبيل المثال، المقالات وصور الأفاتار والجداول الزمنية على وسائل التواصل الاجتماعي وقوائم الصدارة في الألعاب
وهذا يعني أنّ المستخدمين على الإنترنت يحصلون على أحدث محتوى، بينما يحصل المستخدمون بلا إنترنت على نسخة قديمة مخزّنة مؤقتًا. في حال نجاح طلب الشبكة، من المرجّح أنّك تريد تعديل إدخال ذاكرة التخزين المؤقت.
ومع ذلك، تتضمّن هذه الطريقة عيوبًا. إذا كان اتصال المستخدم متقطعًا أو بطيئًا، عليه الانتظار إلى أن يتعذّر الاتصال بالشبكة قبل أن يتمكّن من الوصول إلى المحتوى المقبول تمامًا والمخزّن على جهازه. قد يستغرق ذلك وقتًا طويلاً جدًا ويؤدي إلى تجربة استخدام محبطة. للحصول على حلّ أفضل، اطّلِع على النمط التالي، التخزين المؤقت ثم الشبكة.
self.addEventListener('fetch', function (event) {
event.respondWith(
fetch(event.request).catch(function () {
return caches.match(event.request);
}),
);
});
ذاكرة التخزين المؤقت ثم الشبكة
مناسبة لـ: المحتوى الذي يتم تعديله بشكل متكرر. على سبيل المثال، المقالات والجداول الزمنية على وسائل التواصل الاجتماعي وقوائم الصدارة في الألعاب
يتطلّب ذلك أن تُرسِل الصفحة طلبَين، أحدهما إلى ذاكرة التخزين المؤقت والآخر إلى الشبكة. الفكرة هي عرض البيانات المخزّنة مؤقتًا أولاً، ثم تحديث الصفحة عند وصول بيانات الشبكة.
في بعض الأحيان، يمكنك استبدال البيانات الحالية عند وصول بيانات جديدة (مثل قائمة صدارة في لعبة)، ولكن قد يؤدي ذلك إلى حدوث مشاكل في المحتوى الأكبر حجمًا. بشكل أساسي، لا يجب أن "تختفي" أي عناصر يقرأها المستخدم أو يتفاعل معها.
يضيف Twitter المحتوى الجديد فوق المحتوى القديم ويعدّل موضع التمرير لأسفل كي لا ينقطع المحتوى الذي يراه المستخدم. ويعود السبب في ذلك إلى أنّ Twitter يحتفظ بترتيب خطي إلى حد كبير للمحتوى. لقد اتّبعت هذا النمط في trained-to-thrill لعرض المحتوى على الشاشة بأسرع ما يمكن، مع عرض المحتوى الحديث فور وصوله.
الرمز البرمجي في الصفحة:
var networkDataReceived = false;
startSpinner();
// fetch fresh data
var networkUpdate = fetch('/data.json')
.then(function (response) {
return response.json();
})
.then(function (data) {
networkDataReceived = true;
updatePage(data);
});
// fetch cached data
caches
.match('/data.json')
.then(function (response) {
if (!response) throw Error('No data');
return response.json();
})
.then(function (data) {
// don't overwrite newer network data
if (!networkDataReceived) {
updatePage(data);
}
})
.catch(function () {
// we didn't get cached data, the network is our last hope:
return networkUpdate;
})
.catch(showErrorMessage)
.then(stopSpinner);
الرمز البرمجي في عامل الخدمة:
يجب دائمًا الانتقال إلى الشبكة وتعديل ذاكرة التخزين المؤقت أثناء التنقل.
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open('mysite-dynamic').then(function (cache) {
return fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
});
}),
);
});
في trained-to-thrill، تغلّبتُ على هذه المشكلة باستخدام XHR بدلاً من fetch، واستغلال عنوان Accept لإخبار مشغّل الخدمات بمكان الحصول على النتيجة (رمز الصفحة، رمز مشغّل الخدمات).
الخيار الاحتياطي العام
إذا تعذّر عرض أي محتوى من ذاكرة التخزين المؤقت أو الشبكة، قدِّم محتوًى احتياطيًا عامًا.
مناسبة لما يلي: الصور الثانوية، مثل الصور الرمزية وطلبات POST التي تعذّر تنفيذها وصفحة "غير متوفّرة في وضع عدم الاتصال بالإنترنت".
self.addEventListener('fetch', function (event) {
event.respondWith(
// Try the cache
caches
.match(event.request)
.then(function (response) {
// Fall back to network
return response || fetch(event.request);
})
.catch(function () {
// If both fail, show a generic fallback:
return caches.match('/offline.html');
// However, in reality you'd have many different
// fallbacks, depending on URL and headers.
// Eg, a fallback silhouette image for avatars.
}),
);
});
من المحتمل أن يكون العنصر الاحتياطي متطلب تثبيت.
إذا كانت صفحتك تنشر رسالة إلكترونية، قد يعود عامل الخدمة إلى تخزين الرسالة الإلكترونية في صندوق صادر في IndexedDB والرد بإخبار الصفحة بأنّ عملية الإرسال تعذّر تنفيذها ولكن تم الاحتفاظ بالبيانات بنجاح.
إنشاء النماذج من جهة عامل الخدمة
الحالات المناسبة: الصفحات التي لا يمكن تخزين استجابة الخادم لها مؤقتًا
عرض الصفحات على الخادم أسرع، ولكن قد يعني ذلك تضمين بيانات الحالة التي قد لا تكون منطقية في ذاكرة التخزين المؤقت، مثل حالة تسجيل الدخول. إذا كان مشغّل الخدمات يتحكّم في صفحتك، يمكنك اختيار طلب بيانات JSON مع نموذج وعرض هذا النموذج بدلاً من ذلك.
importScripts('templating-engine.js');
self.addEventListener('fetch', function (event) {
var requestURL = new URL(event.request.url);
event.respondWith(
Promise.all([
caches.match('/article-template.html').then(function (response) {
return response.text();
}),
caches.match(requestURL.path + '.json').then(function (response) {
return response.json();
}),
]).then(function (responses) {
var template = responses[0];
var data = responses[1];
return new Response(renderTemplate(template, data), {
headers: {
'Content-Type': 'text/html',
},
});
}),
);
});
وضع كل العناصر معًا
لا يقتصر الأمر على إحدى هذه الطرق. في الواقع، من المحتمل أن تستخدم العديد منها حسب عنوان URL للطلب. على سبيل المثال، تستخدم trained-to-thrill ما يلي:
- التخزين المؤقت عند التثبيت، لواجهة المستخدم الثابتة والسلوك
- التخزين المؤقت عند استجابة الشبكة لصور Flickr وبياناتها
- استرداد البيانات من ذاكرة التخزين المؤقت، ثم الرجوع إلى الشبكة لمعظم الطلبات
- استرجاع البيانات من ذاكرة التخزين المؤقت، ثم من الشبكة، لنتائج البحث على Flickr
ما عليك سوى الاطّلاع على الطلب وتحديد الإجراء المناسب:
self.addEventListener('fetch', function (event) {
// Parse the URL:
var requestURL = new URL(event.request.url);
// Handle requests to a particular host specifically
if (requestURL.hostname == 'api.example.com') {
event.respondWith(/* some combination of patterns */);
return;
}
// Routing for local URLs
if (requestURL.origin == location.origin) {
// Handle article URLs
if (/^\/article\//.test(requestURL.pathname)) {
event.respondWith(/* some other combination of patterns */);
return;
}
if (/\.webp$/.test(requestURL.pathname)) {
event.respondWith(/* some other combination of patterns */);
return;
}
if (request.method == 'POST') {
event.respondWith(/* some other combination of patterns */);
return;
}
if (/cheese/.test(requestURL.pathname)) {
event.respondWith(
new Response('Flagrant cheese error', {
status: 512,
}),
);
return;
}
}
// A sensible default pattern
event.respondWith(
caches.match(event.request).then(function (response) {
return response || fetch(event.request);
}),
);
});
محتوى إضافي للقراءة
- برامج الخدمة وواجهة برمجة التطبيقات Cache Storage API
- JavaScript Promises—an Introduction: دليل حول الوعود
الساعات المعتمَدة
بالنسبة إلى الرموز الجميلة:
- Code من buzzyrobot
- التقويم من Scott Lewis
- شبكة من "بن ريزو"
- SD من Thomas Le Bas
- وحدة المعالجة المركزية من iconsmind.com
- المهملات من trasnik
- إشعار من @daosme
- Layout من Mister Pixel
- Cloud من تأليف P.J. Onori
وأودّ أن أشكر Jeff Posnick على رصد العديد من الأخطاء قبل أن أنقر على "نشر".