لمحة عن ميزة "الجلب في الخلفية"

في عام 2015، قدمنا ميزة "مزامنة الخلفية" التي تتيح عامل الخدمة لتأجيل العمل حتى يكون لدى المستخدم إمكانية الاتصال. هذا يعني أن المستخدم يمكنه كتابة ثم اضغط على إرسال، ثم يغادر الموقع مع العلم أنه سيتم إرسال الرسالة إما الآن أو عند الاتصال.

وهي ميزة مفيدة، ولكنها تتطلب أن يكون عامل الخدمة على قيد الحياة طوال مدة جلب. هذه ليست مشكلة في فترات قصيرة من العمل مثل إرسال رسالة، ولكن إذا استغرقت المهمة حيث سيؤدي المتصفح إلى إنهاء عامل الخدمة، وإلا فقد يمثل ذلك خطرًا على خصوصية المستخدم البطارية.

لذا، ماذا لو احتجت إلى تنزيل محتوى قد يستغرق وقتًا طويلاً، مثل فيلم أو ملفات بودكاست المستويات في اللعبة. ولهذا السبب، تم استخدام ميزة جلب الخلفية.

تتوفّر ميزة الجلب في الخلفية بشكل تلقائي منذ الإصدار Chrome 74.

إليك عرض توضيحي سريع مدته دقيقتان يوضحان الحالة التقليدية للأشياء مقارنةً باستخدام ميزة الجلب في الخلفية:

جرِّب العرض التوضيحي بنفسك وتصفّح الرمز.

آلية العمل

تعمل عملية الجلب في الخلفية على النحو التالي:

  1. يمكنك الطلب من المتصفّح تنفيذ مجموعة من عمليات الجلب في الخلفية.
  2. يجلب المتصفح تلك الأشياء، ويعرض التقدم للمستخدم.
  3. بعد اكتمال عملية الجلب أو تعذُّر إكمالها، يفتح المتصفّح مشغّل الخدمات وينشّط حدثًا. لإخبارك بما حدث. هذا هو المكان الذي تقرر فيه ما يجب أن تفعله بالردود، إن وجد.

وإذا أغلق المستخدم صفحات على موقعك الإلكتروني بعد الخطوة 1، لا بأس في ذلك، ستستمر عملية التنزيل. لأنّ مدى وضوح عملية جلب البيانات ويسهل إلغاءها، وليس هناك أي قلق بشأن الخصوصية من منظور لمزامنة البيانات في الخلفية. لا داعي للقلق لأنّ عامل الخدمة لا يعمل بشكل متواصل. من إساءة استخدام النظام، مثل تعدين بيتكوين في الخلفية.

في بعض الأنظمة الأساسية (مثل Android)، يمكن أن يتم إغلاق المتصفح بعد الخطوة 1، المتصفّح الذي يسلّم الجلب إلى نظام التشغيل.

إذا بدأ المستخدم عملية التنزيل بلا اتصال بالإنترنت أو انقطع اتصاله بالإنترنت أثناء عملية التنزيل، يتم استخدام الخلفية سيتم إيقاف الجلب مؤقتًا واستئنافها لاحقًا.

واجهة برمجة التطبيقات

اكتشاف الميزات

وكما هو الحال مع أي ميزة جديدة، تحتاج إلى معرفة ما إذا كان المتصفّح يتيحها أم لا. بالنسبة إلى ميزة الجلب في الخلفية، بسيطة مثل:

if ('BackgroundFetchManager' in self) {
  // This browser supports Background Fetch!
}

بدء استرجاع البيانات في الخلفية

تتأثر واجهة برمجة التطبيقات الرئيسية بتسجيل عامل الخدمة، لذا احرص على تسجيل مشغّل الخدمات أولاً. بعد ذلك:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
    title: 'Episode 5: Interesting things.',
    icons: [{
      sizes: '300x300',
      src: '/ep-5-icon.png',
      type: 'image/png',
    }],
    downloadTotal: 60 * 1024 * 1024,
  });
});

تستخدم backgroundFetch.fetch ثلاث وسيطات:

المعلمات
id string
تحدّد هذه الميزة الجلب في الخلفية بشكل فريد.

سيتم رفض "backgroundFetch.fetch" إذا كان رقم التعريف يطابق خلفية حالية. جلب.

requests Array<Request|string>
العناصر المطلوب جلبها. يتم التعامل مع السلاسل باعتبارها عناوين URL ويتم تحويلها إلى Request عبر new Request(theString).

يمكنك استرجاع محتوى من مصادر أخرى طالما أنّ الموارد تسمح بذلك من خلال CORS.

ملاحظة: لا يدعم Chrome حاليًا الطلبات التي قد تتطلب طلبًا تمهيديًا بسياسة CORS.

options كائن قد يتضمّن ما يلي:
options.title string
عنوان للمتصفِّح يعرضه مع مستوى التقدّم.
options.icons Array<IconDefinition>
يشير ذلك المصطلح إلى مصفوفة من العناصر التي تتضمّن "src" و"size" و"type".
options.downloadTotal number
الحجم الإجمالي لنصات الاستجابة (بعد فك ضغطها باستخدام gzip).

وعلى الرغم من أنّ هذه الخطوة اختيارية، إلا أنّنا ننصحك بشدة بتقديمها. يتم استخدامها لسرد للمستخدم حجم التنزيل، وتوفير معلومات التقدم. في حال عدم تقديم فسيُخبر المتصفح المستخدم بأنّ الحجم غير معروف، وبالتالي قد يكون احتمالية إلغاء التنزيل.

إذا تجاوزت عمليات تنزيل استرجاع البيانات في الخلفية الرقم الوارد هنا، سيتم إيقافها. من المهم إذا كان حجم الملف الذي سيتم تنزيله أصغر من downloadTotal، التأكد من إجمالي التنزيل، فمن الأفضل توخي الحذر.

ترجع "backgroundFetch.fetch" وعودًا يتم حلّه من خلال "BackgroundFetchRegistration". وإلى اللقاء بتناول تفاصيل ذلك لاحقًا. يرفض الوعد إذا اختار المستخدم إيقاف عمليات التنزيل أو رفض المعلَمات المُقدمة غير صالحة.

يتيح لك تقديم العديد من الطلبات لجلب خلفية واحدة دمج الأشياء التي تعتبر شيء واحد للمستخدم. فعلى سبيل المثال، قد يتم تقسيم الفيلم إلى آلاف الموارد من الموارد (بشكل نموذجي مع MPEG-DASH), وتوفّر موارد إضافية مثل الصور يمكن أن ينتشر مستوى من اللعبة عبر العديد موارد جافا سكريبت والصور والصوت. ولكن بالنسبة إلى المستخدم، يتعلق الأمر فقط "بالفيلم" أو "المستوى".

الحصول على أداة استرجاع حالية للخلفية

يمكنك الحصول على عملية جلب حالية للخلفية على النحو التالي:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

...عن طريق ضبط id (المعرّف) لعملية استرجاع البيانات في الخلفية التي تريدها. يتم إرجاع undefined من قِبل "get" في حال عدم توفّر جلب نشط في الخلفية باستخدام هذا المعرّف.

يعتبر الجلب في الخلفية "نشطًا" منذ لحظة تسجيلها، إلى أن يتم ذلك بنجاح، أو فشله أو إلغائه.

يمكنك الحصول على قائمة بجميع عمليات الجلب النشطة في الخلفية باستخدام getIds:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

عمليات تسجيل الجلب في الخلفية

يتميز BackgroundFetchRegistration (bgFetch في الأمثلة أعلاه) بما يلي:

أماكن إقامة
id string
معرّف عملية الاسترجاع في الخلفية:
uploadTotal number
عدد وحدات البايت المراد إرسالها إلى الخادم.
uploaded number
عدد وحدات البايت التي تم إرسالها بنجاح.
downloadTotal number
القيمة التي تمّ تقديمها عند تسجيل عملية الاسترجاع في الخلفية صفر.
downloaded number
عدد وحدات البايت التي تم استلامها بنجاح.

وقد تنخفض هذه القيمة. على سبيل المثال، إذا انقطع الاتصال ولم يتمكن التنزيل إعادة تشغيل، في هذه الحالة سيعيد المتصفح تشغيل الجلب لهذا المورد من البداية.

result

يجب استخدام إحدى السمات التالية:

  • "" - عملية الاسترجاع في الخلفية نشطة، لذلك ليست هناك نتائج بعد.
  • "success": تم جلب الخلفية بنجاح.
  • "failure": تعذَّر استرجاع البيانات في الخلفية. لا تظهر هذه القيمة إلا عندما إخفاق الجلب في الخلفية تمامًا، كما هو الحال في المتصفح لا يمكن إعادة المحاولة/الاستئناف.
failureReason

يجب استخدام إحدى السمات التالية:

  • "": لم تفشل عملية استرجاع البيانات في الخلفية.
  • "aborted" – ألغى المستخدم عملية الجلب في الخلفية تم الاتصال بـ abort().
  • "bad-status": إذا كانت حالة أحد الردود غير مقبولة، مثلاً 404.
  • "fetch-error": تعذّر تنفيذ إحدى عمليات الجلب لسبب آخر، على سبيل المثال. بروتوكول CORS أو MIX أو استجابة جزئية غير صالحة أو فشل عام في الشبكة لعملية استرجاع لا يمكن إعادة المحاولة.
  • "quota-exceeded": تم بلوغ مساحة التخزين المتوفّرة أثناء الخلفية. جلب.
  • "download-total-exceeded" - قيمة "downloadTotal" المقدَّمة كانت تجاوز.
recordsAvailable boolean
هل يمكن الوصول إلى الطلبات أو الردود الأساسية؟

عندما يصبح هذا خطأ، لا يمكن استخدام match ولا يمكن استخدام matchAll.

الطُرق
abort() تعرض Promise<boolean>
إلغاء عملية الاسترجاع في الخلفية.

يتم حل الوعد الذي تم إرجاعه بشكل صحيح في حال إلغاء عملية الجلب بنجاح.

matchAll(request, opts) المرتجعات Promise<Array<BackgroundFetchRecord>>
الحصول على الطلبات والردود.

الوسيطة هنا هي نفس ذاكرة التخزين المؤقت API. الاتصال بدون وسيطات يؤدي وعدًا بالحفاظ على جميع السجلات.

انظر أدناه للحصول على مزيد من التفاصيل.

match(request, opts) عرض Promise<BackgroundFetchRecord>
على النحو الوارد أعلاه، ولكن تتم مطابقته مع المطابقة الأولى.
فعاليات
progress يتم الإطلاق عندما يكون أي من uploaded أو downloaded أو result أو تغيير في failureReason

تتبُّع مستوى التقدّم

ويمكن إجراء ذلك من خلال حدث "progress". تذكَّر أنّ downloadTotal هي أي قيمة أو 0 إذا لم يتم تقديم أي قيمة.

bgFetch.addEventListener('progress', () => {
  // If we didn't provide a total, we can't provide a %.
  if (!bgFetch.downloadTotal) return;

  const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
  console.log(`Download progress: ${percent}%`);
});

الحصول على الطلبات والردود

bgFetch.match('/ep-5.mp3').then(async (record) => {
  if (!record) {
    console.log('No record found');
    return;
  }

  console.log(`Here's the request`, record.request);
  const response = await record.responseReady;
  console.log(`And here's the response`, response);
});

record هو BackgroundFetchRecord، ويبدو على النحو التالي:

أماكن إقامة
request Request
الطلب الذي تم تقديمه
responseReady Promise<Response>
الردّ الذي تم استرجاعه

الرد متأخِّر عن وعود لأنّه ربما لم يتم تلقّيه بعد. الموعد النهائي سيتم رفضه في حال فشل الجلب.

أحداث مشغّل الخدمات

فعاليات
backgroundfetchsuccess تم استرجاع كل البيانات بنجاح.
backgroundfetchfailure تعذّر استرجاع واحدة أو أكثر.
backgroundfetchabort تعذّرت عملية جلب واحدة أو أكثر.

هذا مفيد حقًا فقط إذا كنت تريد إجراء تنظيف من البيانات ذات الصلة.

backgroundfetchclick نقر المستخدم على واجهة مستخدم تقدّم عملية التنزيل.

تحتوي كائنات الحدث على ما يلي:

أماكن إقامة
registration BackgroundFetchRegistration
الطُرق
updateUI({ title, icons }) للسماح لك بتغيير العنوان/الرموز التي ضبطتها في البداية. يعد هذا اختياريًا، لكنه يتيح لك وتوفر المزيد من السياق إذا لزم الأمر. يمكنك إجراء ذلك *مرة* فقط خلال backgroundfetchsuccess وbackgroundfetchfailure حدث.

التفاعل مع النجاح/الفشل

لقد سبق لنا عرض حدث progress، ولكن هذا الإجراء مفيد فقط عندما يكون لدى المستخدم صفحة مفتوحة موقعك الإلكتروني. تتمثل الفائدة الرئيسية من استرجاع البيانات في الخلفية في استمرار سير الأمور بعد مغادرة المستخدم الصفحة، أو حتى إغلاق المتصفح.

إذا اكتملت عملية استرجاع البيانات في الخلفية بنجاح، سيتلقّى عامل الخدمة backgroundfetchsuccess، وسيكون event.registration هو تسجيل الاسترجاع في الخلفية.

بعد هذا الحدث، لن تتمكّن من الوصول إلى الطلبات والردود التي تم جلبها، لذا إذا أردت واحتفظ بها، وانقلها إلى مكان مثل واجهة برمجة تطبيقات ذاكرة التخزين المؤقت.

كما هو الحال مع معظم أحداث مشغّلي الخدمات، استخدِم event.waitUntil حتى يعرف عامل الخدمة موعد الحدث. مكتملة.

على سبيل المثال، في مشغّل الخدمات:

addEventListener('backgroundfetchsuccess', (event) => {
  const bgFetch = event.registration;

  event.waitUntil(async function() {
    // Create/open a cache.
    const cache = await caches.open('downloads');
    // Get all the records.
    const records = await bgFetch.matchAll();
    // Copy each request/response across.
    const promises = records.map(async (record) => {
      const response = await record.responseReady;
      await cache.put(record.request, response);
    });

    // Wait for the copying to complete.
    await Promise.all(promises);

    // Update the progress notification.
    event.updateUI({ title: 'Episode 5 ready to listen!' });
  }());
});

قد يرجع الإخفاق إلى خطأ 404 واحد، وهو ما ربما لم يكن مهمًا بالنسبة إليك، لذا ربما لا تزال تستحق نسخ بعض الردود إلى ذاكرة تخزين مؤقت على النحو الوارد أعلاه.

التفاعل مع النقر

واجهة المستخدم التي تعرض مستوى تقدم التنزيل والنتيجة قابلة للنقر الحدث backgroundfetchclick في عامل الخدمة يتيح لك التفاعل مع ذلك. كما هو موضح أعلاه، ستكون event.registration الخلفية وجلب التسجيل.

الشيء الشائع لفعل هذا الحدث هو فتح نافذة:

addEventListener('backgroundfetchclick', (event) => {
  const bgFetch = event.registration;

  if (bgFetch.result === 'success') {
    clients.openWindow('/latest-podcasts');
  } else {
    clients.openWindow('/download-progress');
  }
});

مراجع إضافية

تصحيح: هناك إصدار سابق من هذه المقالة أشارت عن طريق الخطأ إلى ميزة "جلب الخلفية" على أنّها "معيار ويب". لا تتوفّر واجهة برمجة التطبيقات حاليًا على مسار المعايير، ويمكنك الاطّلاع على المواصفات في WICG كمسودة تقرير مجموعة المنتدى.