بث مباشر لتلقّي ردود فورية

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

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

عند كتابة معالِج حدث fetch، من الشائع تمرير respondWith() Response (أو وعد بإنشاء Response) الذي تحصل عليه من fetch() أو caches.match()، وإنهاء العمل. والخبر السار هو أنّه يمكن بث Response التي تم إنشاؤها باستخدام كل من هاتَين الطريقتَين. والخبر السيئ هو أنّه لا يمكن بث Response التي تم إنشاؤها "يدويًا" ، على الأقل حتى الآن. وهنا يأتي دور واجهة برمجة التطبيقات Streams API.

هل هناك أحداث بث؟

مصدر البيانات هو بث يمكن إنشاؤه ومعالجته بشكل تدريجي، ويوفّر واجهة لقراءة أو كتابة أجزاء غير متزامنة من البيانات، وقد تتوفّر مجموعة فرعية فقط من هذه البيانات في الذاكرة في أي وقت معيّن. في الوقت الحالي، نحن مهتمون بـ ReadableStream، التي يمكن استخدامها لإنشاء كائن Response يتم تمريره إلى fetchEvent.respondWith():

self.addEventListener('fetch', event => {
    var stream = new ReadableStream({
    start(controller) {
        if (/* there's more data */) {
        controller.enqueue(/* your data here */);
        } else {
        controller.close();
        }
    });
    });

    var response = new Response(stream, {
    headers: {'content-type': /* your content-type here */}
    });

    event.respondWith(response);
});

ستتلقّى الصفحة التي أدّى طلبها إلى بدء الحدث fetch استجابة بث فور استدعاء event.respondWith()، وستستمر في القراءة من هذا البث ما دام مشغّل الخدمة يواصل enqueue() بيانات إضافية. إنّ الاستجابة الواردة من مشغّل الخدمة إلى الصفحة هي غير متزامنة حقًا، ويمكننا التحكّم بشكل كامل في ملء البث.

الاستخدامات في الحياة اليومية

ربما لاحظت أنّ المثال السابق يتضمّن بعض التعليقات التي تتضمّن العنصر النائب /* your data here */، وكان قليلاً في تفاصيل التنفيذ الفعلية. كيف سيبدو مثال من العالم الواقعي؟

يقدّم Jake Archibald (على نحو غير مفاجئ) مثالاً رائعًا على استخدام أحداث البث لإنشاء استجابة HTML من مقتطفات HTML متعددة تم تخزينها مؤقتًا، بالإضافة إلى البيانات "الحية" التي يتم بثها عبر fetch()، وفي هذه الحالة، محتوى مدونته.

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

هل لديك بث مباشر؟ أم هي تطبيقات تابعة؟

تركّز أفضل الممارسات الحالية حول استخدام مهام الخدمة لتزويد تطبيقات الويب بالطاقة على نموذج App Shell + المحتوى الديناميكي. يعتمد هذا النهج على التخزين المؤقت بشكلٍ مكثّف لـ "قشرة" تطبيق الويب، أي الحدّ الأدنى من صفحات HTML وJavaScript وCSS اللازمة لعرض البنية والتنسيق، ثم تحميل المحتوى الديناميكي المطلوب لكل صفحة معيّنة من خلال طلب من جهة العميل.

توفّر أحداث البث بديلاً لنموذج "قشرة التطبيق"، وهو نموذج يتم فيه بث استجابة HTML أكثر اكتمالاً إلى المتصفّح عندما ينتقل المستخدم إلى صفحة جديدة. يمكن أن يستخدِم الاستجابة التي يتم بثّها الموارد المخزّنة مؤقتًا، وبالتالي يمكنه الاستمرار في تقديم الجزء الأول من رمز HTML بسرعة، حتى في حال عدم الاتصال بالإنترنت، ولكن ينتهي الأمر بأن تبدو هذه الاستجابات أشبه برسائل الاستجابة التقليدية التي يعرضها الخادم. على سبيل المثال، إذا كان تطبيق الويب لديك يستند إلى نظام إدارة محتوى يُعرِض صفحات HTML من خلال الخادم عن طريق تجميع نماذج جزئية معًا، يؤدي ذلك النموذج مباشرةً إلى استخدام استجابات البث، مع تكرار منطق النماذج في الخدمة العاملة بدلاً من الخادم. كما يوضّح الفيديو التالي، يمكن أن تكون ميزة السرعة التي تقدّمها الردود المعروضة مباشرةً مميّزة في ما يتعلّق بحالة الاستخدام هذه:

من المزايا المهمة لبثّ استجابة HTML بالكامل، ما يفسّر سبب كونه البديل الأسرع في الفيديو، هو أنّ HTML الذي يتم عرضه أثناء طلب التنقّل الأوّلي يمكنه الاستفادة إلى أقصى حدّ من معالج بثّ HTML في المتصفّح. لا يمكن أن تستفيد من عملية تحسين الأداء هذه أجزاء HTML التي يتم إدراجها في مستند بعد تحميل الصفحة (كما هو شائع في نموذج App Shell).

إذا كنت في مراحل التخطيط لتنفيذ الخدمة العاملة، أي نموذج يجب اتّباعه: الردود التي يتم بثّها ويتم عرضها تدريجيًا، أو قشطة خفيفة الوزن مع طلب من جهة العميل للمحتوى الديناميكي؟ ليس من المستغرب أنّ الجواب هو أنّ ذلك يعتمد على ما يلي: ما إذا كان لديك عملية تنفيذ حالية تعتمد على نظام إدارة محتوى ونماذج جزئية (ميزة البث) وما إذا كنت تتوقّع حمولات HTML كبيرة فردية يمكنها الاستفادة من المعالجة التدريجية (ميزة البث) وما إذا كان من الأفضل تمثيل تطبيق الويب كتطبيق صفحة واحدة (ميزة App Shell) وما إذا كنت بحاجة إلى نموذج متوافق حاليًا مع إصدارات الإصدارات الثابتة المتعددة للمتصفّحات (ميزة App Shell).

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

الاطّلاع على تفاصيل أكثر حول أحداث البث

إذا كنت بصدد إنشاء أحداث بث قابلة للقراءة، قد لا يكون مجرد استدعاء controller.enqueue() بشكل عشوائي كافيًا أو فعّالاً. يشرح "جاك" بعض التفاصيل حول كيفية استخدام طُرق start() وpull() وcancel() معًا لإنشاء بث بيانات مخصّص لحالة الاستخدام.

إذا كنت بحاجة إلى مزيد من التفاصيل، يمكنك الاطّلاع على مواصفات Streams.

التوافق

تمّت إضافة إمكانية إنشاء عنصر Response داخل عامل خدمة باستخدام ReadableStream كمصدر له في Chrome 52.

لا يتيح تنفيذ Worker في Firefox حتى الآن الردود المستندة إلى ReadableStream، ولكن هناك خطأ تتبُّع ذي صلة بدعم Streams API يمكنك اتّباعه.

يمكنك تتبُّع مستوى التقدّم في إتاحة واجهة برمجة التطبيقات Streams API بدون البادئة في Edge، بالإضافة إلى إتاحة مشغّل الخدمات بشكل عام، في صفحة حالة المنصة من Microsoft.