برمجة اختيار الموارد باستخدام تعديلات العميل

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

  • تحديد التنسيق المناسب (المتجه مقابل المخطّط)
  • تحديد تنسيقات الترميز المثلى (jpeg وwebp وما إلى ذلك)
  • تحديد إعدادات الضغط المناسبة (الضغط بفقدان البيانات مقابل الضغط بدون فقدان البيانات)
  • تحديد البيانات الوصفية التي يجب الاحتفاظ بها أو إزالتها
  • أنشئ صيغًا متعددة لكل شاشة ودرجة دقة DPR.
  • ...
  • مراعاة نوع الشبكة وسرعتها وإعدادات المستخدم المفضّلة

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

إنّ الإجابة عن سؤال ما هي استراتيجية التحسين الجيدة والمستدامة للصور وغيرها من الموارد التي تتضمّن سمات مشابهة؟ هي بسيطة: التشغيل الآلي. إذا كنت تتمرن على تعديل مواردك يدويًا، فأنت تفعل ذلك بشكل خاطئ: ستنسى، أو ستتقاعس عن تعديلها، أو سيرتكب شخص آخر هذا الخطأ نيابةً عنك، وهذا أمر مضمون.

قصة المطوّر المهتم بالأداء

يتضمّن البحث في مساحة تحسين الصور مرحلتين مختلفتَين: وقت الإنشاء ووقت التشغيل.

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

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

<img src="/image/thing" sizes="50vw"
        alt="image thing displayed at 50% of viewport width">

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

  1. للحصول على أفضل ضغط، تريد استخدام تنسيق الصورة الأمثل لكل عميل: WebP لمتصفّح Chrome وJPEG XR لمتصفّح Edge وJPEG للعملاء الآخرين.
  2. للحصول على أفضل جودة مرئية، عليها إنشاء صيغ متعددة لكل صورة بدرجات دقة مختلفة: 1x و1.5x و2x و2.5x و3x، وقد تحتاج أيضًا إلى إنشاء بعض الصيغ الإضافية.
  3. لتجنُّب عرض وحدات بكسل غير ضرورية، عليها فهم ما تعنيه "‎50% of viewport"، فهناك العديد من مختلف سمات إطار العرض.
  4. من الأفضل أيضًا أن تقدّم تجربة مرنة حيث يتم تلقائيًا عرض درجة دقّة أقل على مستخدمي الشبكات البطيئة. بعد كل شيء، حان وقت مشاهدة المحتوى.
  5. يعرض التطبيق أيضًا بعض عناصر التحكّم التي يستخدمها المستخدمون والتي تؤثّر في موارد الصور التي يجب جلبها، لذا يجب مراعاة ذلك أيضًا.

بعد ذلك، أدركت المصمّمة أنّها بحاجة إلى عرض صورة مختلفة بعرض ‎100% إذا كان حجم إطار العرض صغيرًا لتحسين سهولة القراءة. وهذا يعني أنّه علينا الآن تكرار العملية نفسها لمادة عرض أخرى، ثم جعل عملية الاسترداد مشروطة بحجم إطار العرض. هل ذكرت أنّ هذه المهام صعبة؟ حسنًا، حسنًا، لنبدأ. سيساعدنا عنصر picture في تحقيق نتائج جيدة:

<picture>
    <!-- serve WebP to Chrome and Opera -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w,
        /image/thing-800.webp 800w, /image/thing-1200.webp 1200w,
        /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w"
    type="image/webp">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w,
        /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w,
        /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w"
    type="image/webp">
    <!-- serve JPEGXR to Edge -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpgxr 200w, /image/thing-400.jpgxr 400w,
        /image/thing-800.jpgxr 800w, /image/thing-1200.jpgxr 1200w,
        /image/thing-1600.jpgxr 1600w, /image/thing-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpgxr 200w, /image/thing-crop-400.jpgxr 400w,
        /image/thing-crop-800.jpgxr 800w, /image/thing-crop-1200.jpgxr 1200w,
        /image/thing-crop-1600.jpgxr 1600w, /image/thing-crop-2000.jpgxr 2000w"
    type="image/vnd.ms-photo">
    <!-- serve JPEG to others -->
    <source
    media="(min-width: 50em)"
    sizes="50vw"
    srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w,
        /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w,
        /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
    <source
    sizes="(min-width: 30em) 100vw"
    srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w,
        /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w,
        /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
    <!-- fallback for browsers that don't support picture -->
    <img src="/image/thing.jpg" width="50%">
</picture>

لقد تعاملنا مع الاتجاه الفني واختيار التنسيق وقدّمنا ستة أنواع من كل صورة لمراعاة التباين في معدل البت وعرض مساحة العرض على جهاز العميل. رائع.

لا يسمح لنا عنصر picture بتحديد أي قواعد لكيفية التصرّف استنادًا إلى نوع اتصال العميل أو سرعته. ومع ذلك، فإنّ خوارزمية المعالجة تسمح لوكيل المستخدم بتعديل المورد الذي يتم استرجاعه في بعض الحالات، راجِع الخطوة 5. سنأمل فقط أن يكون وكيل المستخدم ذكياً بالقدر الكافي. (ملاحظة: لا تتوفر هذه الميزة في أي من عمليات التنفيذ الحالية). وبالمثل، لا تتوفّر مخطّطات في عنصر picture للسماح بمنطق خاص بالتطبيق يراعي تفضيلات التطبيق أو المستخدم. للحصول على هذين المقطعَين الأخيرَين، علينا نقل كلّ المنطق أعلاه إلى JavaScript، ولكنّ ذلك سيؤدي إلى فقدان تحسينات الماسح الضوئي المُسبَق التحميل التي يوفّرها picture. حسنًا،

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

اختيار الموارد تلقائيًا باستخدام إشارات العميل

خذ نفسًا عميقًا واضبط نفسك على الإيمان بما يلي، ثم فكِّر في المثال التالي:

<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">
...
<picture>
    <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing">
    <img sizes="100vw" src="/image/thing-crop">
</picture>

على الرغم من أنّ المثال أعلاه كافٍ لتقديم كل الإمكانات نفسها التي يوفّرها ترميز الصورة الأطول أعلاه، إلا أنّه، كما سنرى، يتيح للمطوّر التحكّم الكامل في كيفية جلب موارد الصور واختيارها وتحديد وقت جلبها. يكمن "السحر" في السطر الأول الذي يفعّل الإبلاغ عن نصائح العميل ويطلب من المتصفّح عرض نسبة وحدات البكسل للجهاز (DPR) وعرض viewport (Viewport-Width) للتخطيط وعرض الشاشة المقصود (Width) للموارد على الخادم.

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

يوفّر الإصدار 46 من Chrome دعمًا أصليًا DPR وWidth وViewport-Width للملاحظات. تكون التلميحات غير مفعّلة تلقائيًا، ويكون الرمز <meta http-equiv="Accept-CH" content="..."> أعلاه بمثابة إشارة تفعيل تطلب من Chrome إلحاق الرؤوس المحدّدة بطلبات العميل المُرسَلة. بعد ذلك، لنلقِ نظرة على عناوين الطلب والاستجابة لنموذج طلب صورة:

مخطّط بياني لتفاوض تعديلات البرامج

يعلن متصفّح Chrome عن توافقه مع تنسيق WebP من خلال عنوان طلب Accept، ويعلن متصفّح Edge الجديد بالمثل عن توافقه مع JPEG XR من خلال عنوان Accept.

العناوين الثلاثة التالية للطلب هي عناوين تلميحات العميل التي تُعلِن عن نسبة وحدات البكسل للجهاز الخاص بالعميل (3x)، وعرض إطار عرض التنسيق (460 بكسل)، وعرض العرض المقصود للمورد (230 بكسل). يقدّم ذلك كل المعلومات اللازمة للخادم لاختيار الصيغة المثلى للصورة استنادًا إلى مجموعة سياساته الخاصة: مدى توفّر الموارد التي تم إنشاؤها مسبقًا، وتكلفة إعادة ترميز مورد أو تغيير حجمه، ومدى رواج مورد معيّن، وحمولة الخادم الحالية، وما إلى ذلك. في هذه الحالة تحديدًا، يستخدم الخادم التلميحَين DPR و Width ويعرض موردًا بتنسيق WebP، كما هو موضّح في العناوين Content-Type و Content-DPR وVary.

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

<img src="/image/thing" sizes="50vw"
        alt="image thing displayed at 50% of viewport width">

هل تذكر أيضًا هذا الرجل أعلاه؟ باستخدام إشارات العميل، أصبحت علامة الصورة متوافقة الآن مع نسبة العرض إلى الارتفاع ومساحة العرض والعرض بدون أي ترميز إضافي. إذا كنت بحاجة إلى إضافة اتجاه فني، يمكنك استخدام علامة picture، كما شرحنا أعلاه، وبخلاف ذلك، أصبحت جميع علامات الصور الحالية أكثر ذكاءً. تُحسِّن الإشارات المخصّصة للعملاء عناصر img وpicture الحالية.

التحكّم في اختيار الموارد باستخدام الخدمة العاملة

إنّ ServiceWorker هو في الواقع خادم وكيل من جهة العميل يعمل في المتصفّح. ويقوم باعتراض جميع الطلبات الصادرة ويسمح لك بفحص الردود وإعادة كتابتها وتخزينها مؤقتًا وحتى دمجها. وينطبق الأمر نفسه على الصور، فعند تفعيل "ملاحظات العميل"، يمكن لـ ServiceWorker النشط تحديد طلبات الصور وفحص "ملاحظات العميل" المقدَّمة وتحديد منطق المعالجة الخاص به.

self.onfetch = function(event) {
    var req = event.request.clone();
    console.log("SW received request for: " + req.url)
    for (var entry of req.headers.entries()) {
    console.log("\t" + entry[0] +": " + entry[1])
    }
    ...
}
تعديلات العميل serviceWorker

يمنحك ServiceWorker إمكانية التحكّم الكامل من جهة العميل في اختيار الموارد. هذا أمر بالغ الأهمية. فكِّر في ذلك، لأنّ الخيارات تكاد تكون لا نهائية:

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

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

الأسئلة الشائعة حول تعديلات العميل

  1. أين تتوفّر نصائح العملاء؟ تم طرحها في Chrome 46. قيد المناقشة في Firefox وEdge

  2. لماذا يجب تفعيل ميزة "اقتراحات للعملاء"؟ نريد تقليل الوقت المستغرَق في معالجة المواقع الإلكترونية التي لن تستخدم إشارات العميل. لتفعيل إشارات العميل، يجب أن يقدّم الموقع الإلكتروني عنوان Accept-CH أو توجيه <meta http-equiv> المكافئ في ترميز الصفحة. في حال توفّر أيّ من هذين العنصرَين، سيُرفِق وكيل المستخدم الإشارات المناسبة بجميع طلبات الموارد الفرعية. في المستقبل، قد نوفّر مزيدًا من الآليات للحفاظ على هذا الخيار المفضّل لمصدر معيّن، ما سيسمح بعرض الإشارات نفسها عند تلقّي طلبات التنقّل.

  3. لماذا نحتاج إلى تلميحات العميل إذا كان لدينا ServiceWorker؟ لا يمكن لـ ServiceWorker الوصول إلى معلومات التنسيق والموارد وعرض إطار العرض. على الأقل، لا يمكن ذلك بدون إجراء عمليات اتصالات مكرّرة مكلفة و تأخير طلب الصورة بشكل كبير، مثلاً عندما يبدأ معالج التحميل المُسبَق في طلب صورة. يتم دمج إشارات العميل مع المتصفّح لإتاحة هذه البيانات كجزء من الطلب.

  4. هل تُستخدَم نصائح العميل لموارد الصور فقط؟ إنّ حالة الاستخدام الأساسية التي تستند إليها إشارات DPR وViewport-Width وWidth هي تفعيل اختيار الموارد لمواد عرض الصور. ومع ذلك، يتم إرسال التلميحَين نفسهَين لجميع الموارد الفرعية بغض النظر عن نوعها، على سبيل المثال، تحصل طلبات CSS وJavaScript أيضًا على المعلومات نفسها ويمكن استخدامها لتحسين هذه الموارد أيضًا.

  5. لا تُبلغ بعض طلبات الصور عن العرض، لماذا؟ قد لا يعرف المتصفّح عرض العرض المقصود لأنّ الموقع الإلكتروني يعتمد على الحجم الأساسي للصورة. نتيجةً لذلك، يتم حذف التلميح Width لطلبات العرض هذه، والطلبات التي لا تتضمّن "عرض العرض"، مثل مورد JavaScript. لتلقّي نصائح بشأن العرض، احرص على تحديد قيمة sizes في صورك.

  6. ماذا عن <insert my favorite hint>؟ يتيح ServiceWorker للمطوّرين اعتراض جميع الطلبات الصادرة وتعديلها (مثل إضافة عناوين جديدة). على سبيل المثال، من السهل إضافة معلومات مستندة إلى NetInfo للإشارة إلى نوع الاتصال الحالي. راجِع "إعداد تقارير الإمكانات باستخدام ServiceWorker". يتم تنفيذ التلميحات "المضمّنة" المضمّنة في Chrome (DPR وWidth وResource-Width) في المتصفّح لأنّ التنفيذ المستنِد إلى SW فقط سيؤخّر جميع طلبات الصور.

  7. أين يمكنني الاطّلاع على مزيد من المعلومات ومشاهدة المزيد من العروض التوضيحية؟ يمكنك الاطّلاع على المستند التوضيحي ولا تتردد في فتح مشكلة على GitHub إذا كانت لديك ملاحظات أو أسئلة أخرى.