التعامل مع الفعاليات مع موظفي الخدمات

دليل توجيهي يتناول مفاهيم مشغّلي الخدمات الإضافية

نظرة عامة

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

  • سجِّل مشغّل الخدمات واستورِد الوحدات.
  • عليك تصحيح الأخطاء في مشغّل خدمات الإضافات.
  • إدارة الحالة والتعامل مع الأحداث
  • تشغيل الأحداث الدورية
  • التواصل مع النصوص البرمجية للمحتوى.

قبل البدء

يفترض هذا الدليل أنّك تملك الخبرة الأساسية في تطوير المواقع الإلكترونية. ننصحك بمراجعة الإضافات 101 وHello World للحصول على مقدمة عن وتطوير الإضافات.

إنشاء الإضافة

ابدأ بإنشاء دليل جديد باسم quick-api-reference للاحتفاظ بملفات الإضافة، أو نزِّل رمز المصدر من مستودع نماذج GitHub.

الخطوة 1: تسجيل مشغّل الخدمات

أنشئ ملف البيان في جذر المشروع وأضِف الرمز التالي:

manifest.json:

{
  "manifest_version": 3,
  "name": "Open extension API reference",
  "version": "1.0.0",
  "icons": {
    "16": "images/icon-16.png",
    "128": "images/icon-128.png"
  },
  "background": {
    "service_worker": "service-worker.js"
  }
}

تسجِّل الإضافات مشغِّل الخدمات الخاص بها في البيان الذي يأخذ ملف JavaScript واحدًا فقط. ليس هناك حاجة للاتصال بـ navigator.serviceWorker.register()، كما هو الحال في صفحة ويب.

أنشئ مجلد images ثم نزِّل الرموز فيه.

يمكنك الاطّلاع على الخطوات الأولى في الدليل التعليمي الخاص بميزة "وقت القراءة" لمزيد من المعلومات حول البيانات الوصفية ورموز الإضافة في البيان.

الخطوة 2: استيراد وحدات متعددة لمشغّلي الخدمات

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

manifest.json:

{
 "background": {
    "service_worker": "service-worker.js",
    "type": "module"
  },
}

أنشئ ملف service-worker.js واستورِد وحدتَين:

import './sw-omnibox.js';
import './sw-tips.js';

أنشئ هذه الملفات وأضف سجل وحدة تحكم إلى كل ملف.

sw-hybrid.js:

console.log("sw-omnibox.js");

sw-tips.js:

console.log("sw-tips.js");

راجِع استيراد النصوص البرمجية لمعرفة المزيد من المعلومات عن الطرق الأخرى لاستيراد ملفات متعدّدة إلى مشغّل الخدمات.

اختياري: تصحيح أخطاء مشغِّل الخدمة

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

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

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

والآن، اقطع الإضافة لمعرفة مكان وجود الأخطاء. ويمكنك إجراء ذلك من خلال حذف " .js". من عملية استيراد './sw-omnibox.js' في ملف service-worker.js. لن يتمكن Chrome من تسجيل مشغّل الخدمات.

ارجع إلى chrome://extensions وأعِد تحميل الإضافة. ستظهر لك خطآن:

Service worker registration failed. Status code: 3.

An unknown error occurred when fetching the script.

راجِع إضافات تصحيح الأخطاء للاطّلاع على مزيد من الطرق التي يمكن من خلالها تصحيح أخطاء مشغّل خدمة الإضافات.

الخطوة 4: تهيئة الحالة

وسيوقف Chrome مشغِّلي الخدمات إذا لم تكن هناك حاجة إليهم. نستخدم واجهة برمجة التطبيقات chrome.storage للحفاظ على الحالة في جميع جلسات مشغّل الخدمات. للوصول إلى مساحة التخزين، علينا طلب إذن في ملف البيان:

manifest.json:

{
  ...
  "permissions": ["storage"],
}

أولاً، احفظ الاقتراحات الافتراضية في التخزين. يمكننا ضبط الحالة عند تثبيت الإضافة لأول مرة من خلال الاستماع إلى حدث runtime.onInstalled():

sw-hybrid.js:

...
// Save default API suggestions
chrome.runtime.onInstalled.addListener(({ reason }) => {
  if (reason === 'install') {
    chrome.storage.local.set({
      apiSuggestions: ['tabs', 'storage', 'scripting']
    });
  }
});

لا يملك مشغّلو الخدمة إمكانية الوصول مباشرةً إلى كائن النافذة، وبالتالي لا يمكنهم استخدام. window.localStorage لتخزين القيم. كما أن عاملي الخدمات عبارة عن بيئات تنفيذ قصيرة الأجل؛ يتم إنهاؤها بشكل متكرر طوال جلسة متصفح المستخدم، مما يجعلها غير متوافقة مع والمتغيرات العمومية. بدلاً من ذلك، يمكنك استخدام أداة chrome.storage.local التي تخزِّن البيانات على الجهاز المحلي.

يمكنك الاطّلاع على مقالة الاحتفاظ بالبيانات بدلاً من استخدام المتغيّرات العمومية للتعرّف على خيارات التخزين الأخرى للعاملين في الخدمات الإضافية.

الخطوة 5: تسجيل الأحداث

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

في هذا المثال، سنستخدم واجهة برمجة التطبيقات chrome.omnibox، ولكن يجب أولاً الإعلان عن مشغِّل الكلمة الرئيسية للمربّع المتعدد الاستخدامات في البيان:

manifest.json:

{
  ...
  "minimum_chrome_version": "102",
  "omnibox": {
    "keyword": "api"
  },
}

يمكنك الآن تسجيل أدوات معالجة أحداث المربّع المتعدد الاستخدامات في المستوى الأعلى من النص البرمجي. عندما يُدخل المستخدم الكلمة الرئيسية للمربّع المتعدد الاستخدامات (api) في شريط العناوين متبوعًا بعلامة تبويب أو مساحة، سيعرض Chrome قائمة بالاقتراحات استنادًا إلى الكلمات الرئيسية في مساحة التخزين. إنّ حدث onInputChanged()، الذي يأخذ البيانات التي أدخلها المستخدم الحالي والكائن suggestResult، مسؤول عن تعبئة هذه الاقتراحات.

sw-hybrid.js:

...
const URL_CHROME_EXTENSIONS_DOC =
  'https://developer.chrome.com/docs/extensions/reference/';
const NUMBER_OF_PREVIOUS_SEARCHES = 4;

// Display the suggestions after user starts typing
chrome.omnibox.onInputChanged.addListener(async (input, suggest) => {
  await chrome.omnibox.setDefaultSuggestion({
    description: 'Enter a Chrome API or choose from past searches'
  });
  const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
  const suggestions = apiSuggestions.map((api) => {
    return { content: api, description: `Open chrome.${api} API` };
  });
  suggest(suggestions);
});

بعد أن يختار المستخدم اقتراحًا، سيفتح onInputEntered() الصفحة المرجعية المقابلة لواجهة Chrome API.

sw-hybrid.js:

...
// Open the reference page of the chosen API
chrome.omnibox.onInputEntered.addListener((input) => {
  chrome.tabs.create({ url: URL_CHROME_EXTENSIONS_DOC + input });
  // Save the latest keyword
  updateHistory(input);
});

تستخدم الدالة updateHistory() إدخال المربّع المتعدد الاستخدامات وتحفظه في storage.local. وبهذه الطريقة، يمكن استخدام أحدث عبارة بحث لاحقًا كاقتراح لمربّع متعدد الاستخدامات.

sw-hybrid.js:

...
async function updateHistory(input) {
  const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
  apiSuggestions.unshift(input);
  apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
  return chrome.storage.local.set({ apiSuggestions });
}

الخطوة 6: إعداد حدث متكرّر

يتم عادةً استخدام الطريقة setTimeout() أو setInterval() لتنفيذ الإجراءات المتأخرة أو الدورية. المهام. ومع ذلك، قد يتعذّر تنفيذ واجهات برمجة التطبيقات هذه لأنّ أداة الجدولة ستلغي الموقّتات عندما تسمح الخدمة إنهاء أحد العمال. بدلاً من ذلك، يمكن للإضافات استخدام واجهة برمجة تطبيقات chrome.alarms.

يمكنك البدء بطلب إذن ""alarms"" في ملف البيان. بالإضافة إلى ذلك، لجلب نصائح الإضافة من موقع مستضاف بعيد، عليك طلب إذن المضيف:

manifest.json:

{
  ...
  "permissions": ["storage"],
  "permissions": ["storage", "alarms"],
  "host_permissions": ["https://extension-tips.glitch.me/*"],
}

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

sw-tips.js:

// Fetch tip & save in storage
const updateTip = async () => {
  const response = await fetch('https://extension-tips.glitch.me/tips.json');
  const tips = await response.json();
  const randomIndex = Math.floor(Math.random() * tips.length);
  return chrome.storage.local.set({ tip: tips[randomIndex] });
};

const ALARM_NAME = 'tip';

// Check if alarm exists to avoid resetting the timer.
// The alarm might be removed when the browser session restarts.
async function createAlarm() {
  const alarm = await chrome.alarms.get(ALARM_NAME);
  if (typeof alarm === 'undefined') {
    chrome.alarms.create(ALARM_NAME, {
      delayInMinutes: 1,
      periodInMinutes: 1440
    });
    updateTip();
  }
}

createAlarm();

// Update tip once a day
chrome.alarms.onAlarm.addListener(updateTip);

الخطوة 7: التواصل مع سياقات أخرى

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

ابدأ بتعريف النص البرمجي للمحتوى في البيان وإضافة نمط المطابقة المقابل للمستندات المرجعية لواجهة Chrome API.

manifest.json:

{
  ...
  "content_scripts": [
    {
      "matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
      "js": ["content.js"]
    }
  ]
}

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

content.js:

(async () => {
  // Sends a message to the service worker and receives a tip in response
  const { tip } = await chrome.runtime.sendMessage({ greeting: 'tip' });

  const nav = document.querySelector('.upper-tabs > nav');
  
  const tipWidget = createDomElement(`
    <button type="button" popovertarget="tip-popover" popovertargetaction="show" style="padding: 0 12px; height: 36px;">
      <span style="display: block; font: var(--devsite-link-font,500 14px/20px var(--devsite-primary-font-family));">Tip</span>
    </button>
  `);

  const popover = createDomElement(
    `<div id='tip-popover' popover style="margin: auto;">${tip}</div>`
  );

  document.body.append(popover);
  nav.append(tipWidget);
})();

function createDomElement(html) {
  const dom = new DOMParser().parseFromString(html, 'text/html');
  return dom.body.firstElementChild;
}

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

sw-tips.js:

...
// Send tip to content script via messaging
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.greeting === 'tip') {
    chrome.storage.local.get('tip').then(sendResponse);
    return true;
  }
});

اختبار إمكانية العمل

تحقق من أن بنية ملف مشروعك تبدو كما يلي:

تتضمن محتويات مجلد الإضافة: ملف الصور، وملف البيان.json، والخدمة-worker.js، وsw-hybrid.js، وsw-tips.js،
وcontent.js

تحميل الإضافة محليًا

لتحميل إضافة غير مضغوطة في حزمة في وضع مطوّر البرامج، يُرجى اتّباع الخطوات الواردة في Hello world.

فتح صفحة مرجعية

  1. إدخال الكلمة الرئيسية "واجهة برمجة التطبيقات" في شريط عناوين المتصفح.
  2. الضغط على "علامة تبويب" أو "مساحة".
  3. أدخِل الاسم الكامل لواجهة برمجة التطبيقات.
    • أو اختر من قائمة عمليات البحث السابقة
  4. سيتم فتح صفحة جديدة للانتقال إلى الصفحة المرجعية لواجهة برمجة تطبيقات Chrome.

من المفترض أن يظهر على النحو التالي:

مرجع Quick API الذي يفتح مرجع واجهة برمجة التطبيقات الخاص ببيئة التشغيل
إضافة Quick API التي تفتح واجهة Runtime API

فتح نصيحة اليوم

انقر على الزر "نصيحة" في شريط التنقل لفتح نصيحة الإضافة.

فتح النصيحة اليومية في
إضافة Quick API في نصيحة اليوم.

🎯 التحسينات المحتمَلة

بناءً على ما تعلمته اليوم، حاول تحقيق أي مما يلي:

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

استمر في البناء!

تهانينا على إكمال هذا الدليل التعليمي 🎉. يمكنك مواصلة تحسين مهاراتك من خلال إكمال أنشطة دروس تعليمية للمبتدئين:

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

الاطّلاع على معلومات إضافية

لمواصلة المسار التعليمي لعاملي الخدمات الإضافية، ننصحك بالاطّلاع على المقالات التالية: