رویدادها را با کارگران خدمات اداره کنید

آموزشی که مفاهیم کارگر خدمات ترویجی را پوشش می دهد

نمای کلی

این آموزش مقدمه ای را با کارگران سرویس برنامه افزودنی Chrome ارائه می دهد. به عنوان بخشی از این آموزش، افزونه ای خواهید ساخت که به کاربران امکان می دهد با استفاده از omnibox به سرعت به صفحات مرجع Chrome API حرکت کنند. شما یاد خواهید گرفت که چگونه:

  • سرویس‌کار خود را ثبت کنید و ماژول‌ها را وارد کنید.
  • کارمند سرویس برنامه افزودنی خود را اشکال زدایی کنید.
  • مدیریت وضعیت و مدیریت رویدادها.
  • رویدادهای دوره ای را فعال کنید.
  • با اسکریپت های محتوا ارتباط برقرار کنید.

قبل از شروع

این راهنما فرض می کند که شما تجربه اولیه توسعه وب را دارید. برای آشنایی با توسعه برنامه‌های افزودنی، توصیه می‌کنیم برنامه‌های افزودنی 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"
  }
}

برنامه های افزودنی، سرویس دهنده خود را در مانیفست ثبت می کنند که فقط یک فایل جاوا اسکریپت را می گیرد. نیازی به فراخوانی 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-omnibox.js:

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

sw-tips.js:

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

برای آشنایی با روش‌های دیگر وارد کردن چندین فایل در یک سرویس‌دهنده ، وارد کردن اسکریپت‌ها را ببینید.

اختیاری: اشکال زدایی کارگر سرویس

من توضیح خواهم داد که چگونه گزارش کارگر سرویس را پیدا کنم و بدانم چه زمانی خاتمه یافته است. ابتدا دستورالعمل‌های بارگیری یک برنامه افزودنی بدون بسته‌بندی را دنبال کنید.

پس از 30 ثانیه، "سرویس‌کار (غیرفعال)" را مشاهده خواهید کرد که به معنای پایان کار است. برای بررسی روی پیوند "کارگر خدمات (غیرفعال)" کلیک کنید. انیمیشن زیر این را نشان می دهد.

آیا متوجه شده اید که بازرسی کارگر سرویس آن را بیدار کرده است؟ باز کردن Service Worker در Devtools آن را فعال نگه می دارد. برای اطمینان از اینکه برنامه افزودنی شما در هنگام پایان کار سرویس دهنده شما به درستی رفتار می کند، به یاد داشته باشید که DevTools را ببندید.

اکنون، برنامه افزودنی را بشکنید تا بدانید کجا باید خطاها را پیدا کنید. یکی از راه‌های انجام این کار، حذف «.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 API برای تداوم وضعیت در جلسات کارگر سرویس استفاده می‌کنیم. برای دسترسی به فضای ذخیره‌سازی، باید در مانیفست درخواست مجوز کنیم:

manifest.json:

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

ابتدا پیشنهادات پیش فرض را در حافظه ذخیره کنید. می‌توانیم با گوش دادن به رویداد runtime.onInstalled() وضعیت را زمانی که پسوند برای اولین بار نصب می‌شود مقداردهی کنیم:

sw-omnibox.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 API استفاده کنیم، اما ابتدا باید کلیدواژه omnibox را در مانیفست اعلام کنیم:

manifest.json:

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

اکنون شنوندگان رویداد omnibox را در سطح بالای اسکریپت ثبت کنید. وقتی کاربر کلمه کلیدی omnibox ( api ) را در نوار آدرس و سپس برگه یا فاصله وارد می کند، Chrome لیستی از پیشنهادات را بر اساس کلمات کلیدی موجود در فضای ذخیره سازی نمایش می دهد. رویداد onInputChanged() که ورودی کاربر فعلی و یک شی suggestResult را می گیرد، مسئول پر کردن این پیشنهادات است.

sw-omnibox.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-omnibox.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() ورودی omnibox را می گیرد و آن را در storage.local ذخیره می کند. به این ترتیب آخرین عبارت جستجو می تواند بعداً به عنوان پیشنهاد omnibox استفاده شود.

sw-omnibox.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() معمولا برای انجام کارهای تاخیری یا دوره ای استفاده می شوند. با این حال، این APIها ممکن است از کار بیفتند، زیرا زمان‌بندی‌کننده تایمرها را با پایان کار سرویس‌دهنده لغو می‌کند. در عوض، برنامه‌های افزودنی می‌توانند از API 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 API بازدید می کند، اسکریپت محتوای برنامه افزودنی صفحه را با نوک روز به روز می کند. پیامی می فرستد تا انعام روز را از کارمند خدمات درخواست کند.

با اعلام اسکریپت محتوا در مانیفست شروع کنید و الگوی تطابق مربوط به مستندات مرجع 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;
  }
});

تست کنید که کار می کند

بررسی کنید که ساختار فایل پروژه شما به شکل زیر باشد:

محتویات پوشه افزونه: پوشه images، manifest.json، service-worker.js، sw-omnibox.js، sw-tips.js و content.js

برنامه افزودنی خود را به صورت محلی بارگیری کنید

برای بارگیری یک برنامه افزودنی بدون بسته بندی در حالت توسعه دهنده، مراحل Hello world را دنبال کنید.

یک صفحه مرجع باز کنید

  1. کلمه کلیدی "api" را در نوار آدرس مرورگر وارد کنید.
  2. "tab" یا "space" را فشار دهید.
  3. نام کامل API را وارد کنید.
    • یا از لیست جستجوهای گذشته انتخاب کنید
  4. صفحه جدیدی به صفحه مرجع Chrome API باز می شود.

باید به این شکل باشد:

Quick API Reference مرجع api زمان اجرا را باز می کند
پسوند Quick API که Runtime API را باز می کند.

نوک روز را باز کنید

روی دکمه Tip واقع در نوار پیمایش کلیک کنید تا نکته برنامه افزودنی باز شود.

نوک روزانه را باز کنید
برنامه افزودنی Quick API نوک روز را باز می کند.

🎯 پیشرفت های بالقوه

بر اساس آنچه امروز آموخته اید، سعی کنید یکی از موارد زیر را انجام دهید:

  • روش دیگری برای اجرای پیشنهادات omnibox را کاوش کنید.
  • مدال سفارشی خود را برای نمایش نکته برنامه افزودنی ایجاد کنید.
  • یک صفحه اضافی به صفحات API مرجع برنامه های افزودنی وب MDN باز کنید.

به ساختن ادامه بده

به پایان رساندن این آموزش تبریک می گویم 🎉. با تکمیل سایر آموزش های مبتدی به ارتقای سطح مهارت های خود ادامه دهید:

پسوند آنچه خواهید آموخت
زمان خواندن برای درج یک عنصر در مجموعه خاصی از صفحات به طور خودکار.
مدیر زبانه ها برای ایجاد یک پنجره بازشو که برگه های مرورگر را مدیریت می کند.
حالت فوکوس برای اجرای کد در صفحه فعلی پس از کلیک بر روی اکشن افزونه.

به کاوش ادامه دهید

برای ادامه مسیر یادگیری کارکنان خدمات توسعه، توصیه می کنیم مقالات زیر را بررسی کنید: