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

في الوحدة الأخيرة، تم تقديم نظرة عامة على العاملين على الويب. يمكن للعاملين على الويب تحسين استجابة الإدخال عن طريق نقل JavaScript خارج سلسلة التعليمات الرئيسية إلى سلاسل محادثات عمال الويب منفصلة، ما يساعد في تحسين التفاعل مع مدى استجابة الصفحة لتفاعلات المستخدم (INP) على موقعك الإلكتروني عندما يكون لديك عمل لا يحتاج إلى وصول مباشر إلى سلسلة التعليمات الرئيسية. مع ذلك، لن تكون النظرة العامة وحدها كافية، وفي هذه الوحدة، يتم تقديم حالة استخدام ملموسة لعامل الويب.

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

مع ذلك، قد يكون منطق استرجاع الصور وتحويلها إلى ArrayBuffer واستخراج بيانات Exif الوصفية مكلفًا في حال تنفيذ ذلك بالكامل على سلسلة التعليمات الرئيسية. لحسن الحظ، يسمح نطاق عامل الويب بهذا العمل خارج السلسلة الرئيسية. بعد ذلك، باستخدام مسار المراسلة لدى عامل الويب، يتم نقل بيانات Exif الوصفية مرة أخرى إلى سلسلة التعليمات الرئيسية كسلسلة HTML ويتم عرضها للمستخدم.

طريقة ظهور سلسلة التعليمات الرئيسية بدون عامل ويب

أولاً، لاحظ كيف تبدو سلسلة التعليمات الرئيسية عندما نقوم بهذا العمل بدون عامل ويب. للقيام بذلك، قم بتنفيذ الخطوات التالية:

  1. افتح علامة تبويب جديدة في Chrome، وافتح "أدوات مطوري البرامج".
  2. افتح لوحة الأداء.
  3. انتقِل إلى https://exif-worker.glitch.me/without-worker.html.
  4. في لوحة الأداء، انقر على تسجيل في أعلى يسار لوحة "أدوات مطوري البرامج".
  5. الصق رابط الصورة هذا - أو أي رابط آخر تختاره يحتوي على بيانات Exif الوصفية - في الحقل وانقر على زر Get that JPEG! (الحصول على هذا JPEG!).
  6. بعد تعبئة الواجهة ببيانات Exif الوصفية، انقر على Register (تسجيل) مرة أخرى لإيقاف التسجيل.
يعرض محلّل الأداء نشاط تطبيق أداة استخراج البيانات الوصفية للصور الذي يحدث بالكامل في سلسلة التعليمات الرئيسية. هناك مهمتان مهمتان طويلتان، إحداهما تُجري عملية جلب للحصول على الصورة المطلوبة وفك ترميزها، والأخرى هي استخراج البيانات الوصفية من الصورة.
نشاط سلسلة المحادثات الرئيسية في تطبيق "أداة استخراج البيانات الوصفية للصور". يُرجى العِلم أنّ جميع الأنشطة تحدث في سلسلة التعليمات الرئيسية.

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

  1. يحصل النموذج على الإدخال ويُرسِل طلب fetch للحصول على الجزء الأوليّ من الصورة الذي يحتوي على بيانات Exif الوصفية.
  2. يتم تحويل بيانات الصورة إلى ArrayBuffer.
  3. يُستخدم النص البرمجي exif-reader لاستخراج بيانات Exif الوصفية من الصورة.
  4. يتم سرقة البيانات الوصفية لإنشاء سلسلة HTML، التي تملأ بعد ذلك عارض بيانات التعريف.

الآن قارن ذلك بتنفيذ نفس السلوك، ولكن باستخدام عامل ويب!

مظهر سلسلة التعليمات الرئيسية مع عامل تشغيل على الويب

الآن بعد أن رأيت طريقة استخراج بيانات Exif الوصفية من ملف JPEG على سلسلة التعليمات الرئيسية، ألق نظرة على ما يبدو عليه الأمر عندما يكون هناك عامل ويب في هذا المزيج:

  1. افتح علامة تبويب أخرى في Chrome، ثم افتح "أدوات مطوري البرامج".
  2. افتح لوحة الأداء.
  3. انتقِل إلى https://exif-worker.glitch.me/with-worker.html.
  4. في لوحة الأداء، انقر على زر التسجيل في أعلى يسار الشاشة من لوحة "أدوات مطوري البرامج".
  5. الصِق رابط الصورة هذا في الحقل وانقر على زر الحصول على هذا JPEG.
  6. بعد تعبئة الواجهة ببيانات Exif الوصفية، انقر على زر Record (تسجيل) مرة أخرى لإيقاف التسجيل.
محلّل الأداء يعرض نشاط تطبيق أداة استخراج البيانات الوصفية للصور الذي يحدث في كل من سلسلة التعليمات الرئيسية وسلسلة محادثات عامل الويب وبالرغم من أنّه لا تزال هناك مهام طويلة في سلسلة التعليمات الرئيسية، فإنّها أقصر بكثير، حيث يتم جلب الصور وفك ترميزها واستخراج البيانات الوصفية بالكامل في سلسلة محادثات على الويب. يتضمّن عمل سلسلة التعليمات الرئيسي الوحيد تمرير البيانات من وإلى عامل الويب.
نشاط سلسلة المحادثات الرئيسية في تطبيق "أداة استخراج البيانات الوصفية للصور". يُرجى العِلم أنّ هناك سلسلة محادثات إضافية على الويب يتم فيها تنفيذ معظم الأعمال.

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

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

والآن لنتعمق أكثر في موضوع كود عامل الويب الذي يجعل كل ذلك ممكنًا!

نظرة على رمز عامل الويب

لا يكفي أن نرى الفرق الذي يُحدثه عامل الويب، ولكن من المفيد أيضًا أن تفهم - في هذه الحالة على الأقل - الشكل الذي تبدو عليه هذه التعليمة البرمجية حتى تتمكن من معرفة ما هو ممكن في نطاق العامل على الويب.

ابدأ برمز سلسلة التعليمات الرئيسي الذي يجب أن يحدث قبل أن يتمكن عامل الويب من إدخال الصورة:

// scripts.js

// Register the Exif reader web worker:
const exifWorker = new Worker('/js/with-worker/exif-worker.js');

// We have to send image requests through this proxy due to CORS limitations:
const imageFetchPrefix = 'https://res.cloudinary.com/demo/image/fetch/';

// Necessary elements we need to select:
const imageFetchPanel = document.getElementById('image-fetch');
const imageExifDataPanel = document.getElementById('image-exif-data');
const exifDataPanel = document.getElementById('exif-data');
const imageInput = document.getElementById('image-url');

// What to do when the form is submitted.
document.getElementById('image-form').addEventListener('submit', event => {
  // Don't let the form submit by default:
  event.preventDefault();

  // Send the image URL to the web worker on submit:
  exifWorker.postMessage(`${imageFetchPrefix}${imageInput.value}`);
});

// This listens for the Exif metadata to come back from the web worker:
exifWorker.addEventListener('message', ({ data }) => {
  // This populates the Exif metadata viewer:
  exifDataPanel.innerHTML = data.message;
  imageFetchPanel.style.display = 'none';
  imageExifDataPanel.style.display = 'block';
});

يتم تشغيل هذا الرمز في سلسلة التعليمات الرئيسية وإعداد النموذج لإرسال عنوان URL الخاص بالصورة إلى العامل على الويب. بعد ذلك، يبدأ رمز مشغّل الويب بالعبارة importScripts التي تحمِّل النص البرمجي exif-reader الخارجي، ثم تضبط مسار الرسائل إلى سلسلة التعليمات الرئيسية:

// exif-worker.js

// Import the exif-reader script:
importScripts('/js/with-worker/exifreader.js');

// Set up a messaging pipeline to send the Exif data to the `window`:
self.addEventListener('message', ({ data }) => {
  getExifDataFromImage(data).then(status => {
    self.postMessage(status);
  });
});

يعمل هذا الجزء من JavaScript على إعداد مسار المراسلة بحيث عندما يرسل المستخدم النموذج الذي يتضمّن عنوان URL إلى ملف JPEG، يصل عنوان URL إلى عامل الويب. ومن هناك، يعمل الجزء التالي من الرمز على استخراج بيانات Exif الوصفية من ملف JPEG، ثم إنشاء سلسلة HTML، وإرسال رمز HTML مرة أخرى إلى window ليتم عرضها للمستخدم في النهاية:

// Takes a blob to transform the image data into an `ArrayBuffer`:
// NOTE: these promises are simplified for readability, and don't include
// rejections on failures. Check out the complete web worker code:
// https://glitch.com/edit/#!/exif-worker?path=js%2Fwith-worker%2Fexif-worker.js%3A10%3A5
const readBlobAsArrayBuffer = blob => new Promise(resolve => {
  const reader = new FileReader();

  reader.onload = () => {
    resolve(reader.result);
  };

  reader.readAsArrayBuffer(blob);
});

// Takes the Exif metadata and converts it to a markup string to
// display in the Exif metadata viewer in the DOM:
const exifToMarkup = exif => Object.entries(exif).map(([exifNode, exifData]) => {
  return `
    <details>
      <summary>
        <h2>${exifNode}</h2>
      </summary>
      <p>${exifNode === 'base64' ? `<img src="data:image/jpeg;base64,${exifData}">` : typeof exifData.value === 'undefined' ? exifData : exifData.description || exifData.value}</p>
    </details>
  `;
}).join('');

// Fetches a partial image and gets its Exif data
const getExifDataFromImage = imageUrl => new Promise(resolve => {
  fetch(imageUrl, {
    headers: {
      // Use a range request to only download the first 64 KiB of an image.
      // This ensures bandwidth isn't wasted by downloading what may be a huge
      // JPEG file when all that's needed is the metadata.
      'Range': `bytes=0-${2 ** 10 * 64}`
    }
  }).then(response => {
    if (response.ok) {
      return response.clone().blob();
    }
  }).then(responseBlob => {
    readBlobAsArrayBuffer(responseBlob).then(arrayBuffer => {
      const tags = ExifReader.load(arrayBuffer, {
        expanded: true
      });

      resolve({
        status: true,
        message: Object.values(tags).map(tag => exifToMarkup(tag)).join('')
      });
    });
  });
});

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

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