استبدال صفحات الخلفية أو الأحداث بمشغّل خدمات
يستبدل مشغّل الخدمة صفحة الخلفية أو صفحة الحدث في الإضافة لضمان بقاء رمز الخلفية خارج سلسلة المهام الرئيسية. ويؤدي ذلك إلى تشغيل الإضافات عند الحاجة فقط، ما يوفر الموارد.
كانت صفحات الخلفية عنصرًا أساسيًا في الإضافات منذ طرحها. بعبارة أخرى، توفّر الصفحات التي تعمل في الخلفية بيئة مستقلة عن أي نافذة أو علامة تبويب أخرى. يتيح ذلك للإضافات مراقبة الأحداث واتّخاذ الإجراءات اللازمة استجابةً لها.
توضّح هذه الصفحة مهام تحويل الصفحات التي تعمل في الخلفية إلى عناصر خدمة إضافية. لمزيد من المعلومات عن مشغِّلات خدمات الإضافات بشكل عام، اطّلِع على الدليل التعليمي معالجة الأحداث باستخدام مشغِّلات الخدمات والقسم لمحة عن مشغِّلات خدمات الإضافات.
الاختلافات بين النصوص البرمجية التي تعمل في الخلفية وخدمات إضافة المهام
في بعض السياقات، سترى عناصر خدمة الإضافات التي تُعرف باسم "النصوص البرمجية التي تعمل في الخلفية". على الرغم من أنّ مشغّلي خدمات الإضافات يتم تشغيلهم في الخلفية، إلا أنّ تسميتهم بنصوص برمجية تعمل في الخلفية مضلِّلة إلى حدّ ما لأنّها تشير إلى إمكانات متطابقة. ويمكنك الاطّلاع على الاختلافات أدناه.
التغييرات من الصفحات التي تعمل في الخلفية
هناك عدد من الاختلافات بين مهام الخدمة والصفحات التي تعمل في الخلفية.
- تعمل هذه الطلبات خارج سلسلة المحادثات الرئيسية، ما يعني أنّها لا تتداخل مع محتوى الإضافة.
- وتتمتع هذه الأدوات بإمكانات خاصة، مثل اعتراض أحداث الجلب من مصدر الإضافة، مثل تلك الواردة من نافذة منبثقة لشريط الأدوات.
- ويمكنهم التواصل والتفاعل مع السياقات الأخرى من خلال واجهة العملاء.
التغييرات التي يجب إجراؤها
ستحتاج إلى إجراء بعض التعديلات على الرمز البرمجي لمراعاة الاختلافات بين طريقة عمل النصوص البرمجية التي تعمل في الخلفية وطريقة عمل مهام الخدمة. أولاً، تختلف طريقة تحديد مشغّل الخدمة في ملف البيان عن طريقة تحديد النصوص البرمجية التي تعمل في الخلفية. علاوةً على ذلك:
- وبما أنّه لا يمكنها الوصول إلى DOM أو واجهة
window
، عليك نقل هذه الطلبات إلى واجهة برمجة تطبيقات مختلفة أو إلى مستند خارج الشاشة. - يجب عدم تسجيل أدوات معالجة الأحداث استجابةً للوعود التي تم إرجاعها أو داخل عمليات استدعاء الأحداث.
- وبما أنّها غير متوافقة مع الإصدارات القديمة من
XMLHttpRequest()
، عليك استبدال طلبات البيانات من هذه الواجهة بطلبات البيانات منfetch()
. - وبما أنّها تنتهي عند عدم استخدامها، عليك الاحتفاظ بحالات التطبيق بدلاً من الاعتماد على المتغيّرات الشاملة. يمكن أن يؤدي إنهاء مهام الخدمة أيضًا إلى إنهاء الموقّتات قبل اكتمالها. وعليك استبدالها بمنبّهات.
توضّح هذه الصفحة هذه المهام بالتفصيل.
تعديل الحقل background في البيان
في الإصدار 3 من Manifest، يتم استبدال الصفحات التي تعمل في الخلفية بمشغّل خدمات. في ما يلي التغييرات في البيان.
- استبدِل
"background.scripts"
بـ"background.service_worker"
فيmanifest.json
. يُرجى العلم أنّ حقل"service_worker"
يقبل سلسلة، وليس صفيفًا من السلاسل. - أزِل
"background.persistent"
منmanifest.json
.
{ ... "background": { "scripts": [ "backgroundContextMenus.js", "backgroundOauth.js" ], "persistent": false }, ... }
{ ... "background": { "service_worker": "service_worker.js", "type": "module" } ... }
يقبل الحقل "service_worker"
سلسلة واحدة. لن تحتاج إلى حقل "type"
إلا إذا كنت تستخدم وحدات ES (باستخدام الكلمة الرئيسية import
). ستكون قيمته دائمًا "module"
. لمزيد من المعلومات، يُرجى الاطّلاع على أساسيات مهام الخدمة في الإضافات.
نقل طلبات DOM والنوافذ إلى مستند خارج الشاشة
تحتاج بعض الإضافات إلى الوصول إلى عناصر DOM وعناصر النافذة بدون فتح نافذة أو علامة تبويب جديدة بشكل مرئي. توفّر واجهة برمجة التطبيقات Offscreen API حالات الاستخدام هذه من خلال فتح وإغلاق المستندات غير المعروضة المُضمّنة في الإضافة، بدون إيقاف تجربة المستخدم. باستثناء نقل الرسائل، لا تشارك المستندات التي لا تظهر على الشاشة واجهات برمجة التطبيقات مع سياقات الإضافات الأخرى، ولكنها تعمل كصفحات ويب كاملة يمكن للإضافة التفاعل معها.
لاستخدام Offscreen API، أنشئ مستندًا خارج الشاشة من الخدمة العاملة.
chrome.offscreen.createDocument({
url: chrome.runtime.getURL('offscreen.html'),
reasons: ['CLIPBOARD'],
justification: 'testing the offscreen API',
});
في المستند الذي لا يظهر على الشاشة، يمكنك تنفيذ أي إجراء كنت ستنفّذه سابقًا في نص برمجي في الخلفية. على سبيل المثال، يمكنك نسخ نص محدّد في صفحة المضيف.
let textEl = document.querySelector('#text');
textEl.value = data;
textEl.select();
document.execCommand('copy');
التواصل بين المستندات التي لا تظهر على الشاشة وموظفي خدمة الدعم باستخدام ميزة إرسال الرسائل
تحويل localStorage إلى نوع آخر
لا يمكن استخدام واجهة Storage
لمنصّة الويب (التي يمكن الوصول إليها من window.localStorage
) في مشغّل الخدمات. لحلّ هذه المشكلة، يمكنك اتّخاذ أحد الإجراءَين التاليَين: أولاً، يمكنك استبدالها بطلعات إلى آلية تخزين أخرى. ستلبي مساحة الاسم chrome.storage.local
معظم حالات الاستخدام، ولكن تتوفّر خيارات أخرى.
يمكنك أيضًا نقل المكالمات إلى مستند خارج الشاشة. على سبيل المثال، لنقل البيانات المخزّنة سابقًا في localStorage
إلى آلية أخرى:
- أنشئ مستندًا خارج الشاشة باستخدام سلسلة إجراءات تحويل ومعالج
runtime.onMessage
. - أضِف روتين تحويل إلى المستند الذي لا يظهر على الشاشة.
- في عامل خدمة إضافة Chrome، تحقّق من
chrome.storage
لبياناتك. - إذا لم يتم العثور على بياناتك، يمكنك create مستند غير مرئي والاتصال برقم
runtime.sendMessage()
لبدء عملية التحويل. - في معالِج
runtime.onMessage
الذي أضفته إلى المستند الذي لا يظهر على الشاشة، استخدِم سلسلة إجراءات الإحالة الناجحة.
هناك أيضًا بعض الاختلافات الدقيقة في آلية عمل واجهات برمجة التطبيقات لتخزين الويب في الإضافات. اطّلِع على مزيد من المعلومات في مقالة مساحة التخزين وملفات تعريف الارتباط.
تسجيل أدوات المعالجة بشكل متزامن
لا يمكن ضمان عمل تسجيل مستمع بشكل غير متزامن (على سبيل المثال، داخل وعد أو دالة استدعاء) في Manifest V3. راجِع الرمز البرمجي التالي.
chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
chrome.browserAction.setBadgeText({ text: badgeText });
chrome.browserAction.onClicked.addListener(handleActionClick);
});
يعمل هذا الإجراء مع صفحة دائمة في الخلفية لأنّ الصفحة تعمل باستمرار ولا تتم إعادة بدء تشغيلها أبدًا. في الإصدار 3 من Manifest، ستتم إعادة ضبط الخدمة العاملة عند إرسال الحدث. وهذا يعني أنّه عند بدء الحدث، لن يتم تسجيل أدوات مراقبة الأحداث (لأنّها تتم إضافتها بشكل غير متزامن)، ولن يتم رصد الحدث.
بدلاً من ذلك، انقل تسجيل مستمع الحدث إلى المستوى الأعلى من النص البرمجي. يضمن ذلك أنّ Chrome سيتمكّن من العثور على معالِج النقر الخاص بالإجراء وتنفيذه على الفور، حتى إذا لم تكن الإضافة قد أكملت تنفيذ منطق بدء التشغيل.
chrome.action.onClicked.addListener(handleActionClick);
chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
chrome.action.setBadgeText({ text: badgeText });
});
استبدِل XMLHttpRequest() بـ fetch() العام.
لا يمكن استدعاء XMLHttpRequest()
من عامل خدمة أو إضافة أو غير ذلك. استبدِل المكالمات الواردة من نص الخلفية إلى XMLHttpRequest()
بالمكالمات الواردة إلى fetch()
العام.
const xhr = new XMLHttpRequest(); console.log('UNSENT', xhr.readyState); xhr.open('GET', '/api', true); console.log('OPENED', xhr.readyState); xhr.onload = () => { console.log('DONE', xhr.readyState); }; xhr.send(null);
const response = await fetch('https://www.example.com/greeting.json'') console.log(response.statusText);
حالات الاحتفاظ
وظائف الخدمة مؤقتة، ما يعني أنّه من المرجّح أن يتم تشغيلها وتنفيذها وإنهائها بشكل متكرّر أثناء جلسة المتصفّح للمستخدم. ويعني ذلك أيضًا أنّ البيانات لا تتوفّر على الفور في المتغيّرات العمومية منذ إلغاء السياق السابق. لحلّ هذه المشكلة، استخدِم واجهات برمجة تطبيقات مساحة التخزين كمصدر موثوق للبيانات. سنوضّح لك كيفية إجراء ذلك من خلال مثال.
يستخدم المثال التالي متغيّرًا عامًا لتخزين اسم. في Worker الخدمة، يمكن إعادة ضبط هذا المتغيّر عدة مرات خلال جلسة المتصفّح للمستخدم.
let savedName = undefined; chrome.runtime.onMessage.addListener(({ type, name }) => { if (type === "set-name") { savedName = name; } }); chrome.browserAction.onClicked.addListener((tab) => { chrome.tabs.sendMessage(tab.id, { name: savedName }); });
بالنسبة إلى الإصدار 3 من ملف البيان، استبدِل المتغيّر العام باستدعاء Storage API.
chrome.runtime.onMessage.addListener(({ type, name }) => { if (type === "set-name") { chrome.storage.local.set({ name }); } }); chrome.action.onClicked.addListener(async (tab) => { const { name } = await chrome.storage.local.get(["name"]); chrome.tabs.sendMessage(tab.id, { name }); });
تحويل الموقّتات إلى منبّهات
من الشائع استخدام عمليات متأخرة أو دورية باستخدام الطريقتَين setTimeout()
أو setInterval()
. ومع ذلك، يمكن أن تتعذّر هذه واجهات برمجة التطبيقات في مشغّلات الخدمات لأنّه يتم إلغاء الموقّتات عند إنهاء مشغّل الخدمة.
// 3 minutes in milliseconds const TIMEOUT = 3 * 60 * 1000; setTimeout(() => { chrome.action.setIcon({ path: getRandomIconPath(), }); }, TIMEOUT);
بدلاً من ذلك، استخدِم Alarms API. كما هو الحال مع المستمعين الآخرين، يجب تسجيل مستمعي الإنذارات في أعلى مستوى من النص البرمجي.
async function startAlarm(name, duration) { await chrome.alarms.create(name, { delayInMinutes: 3 }); } chrome.alarms.onAlarm.addListener(() => { chrome.action.setIcon({ path: getRandomIconPath(), }); });
إبقاء الخدمة نشطة
إنّ مشغّلات الخدمات مستندة بطبيعتها إلى الأحداث، وسيتم إنهاءها في حال عدم النشاط. بهذه الطريقة، يمكن لمتصفّح Chrome تحسين أداء الإضافة واستهلاكها للذاكرة. يمكنك الاطّلاع على مزيد من المعلومات في مستندات دورة حياة مهام الخدمة. قد تتطلّب الحالات الاستثنائية اتخاذ إجراءات إضافية لضمان استمرار عمل الخدمة لفترة أطول.
إبقاء عامل الخدمة نشطًا إلى أن تكتمل عملية طويلة الأمد
أثناء عمليات مشغّل الخدمات التي تستغرق وقتًا طويلاً ولا تستدعي واجهات برمجة تطبيقات الإضافات، قد يتم إيقاف مشغّل الخدمات أثناء العملية. تشمل الأمثلة ما يلي:
- طلب
fetch()
يستغرق وقتًا أطول من خمس دقائق (مثل تنزيل ملف كبير على اتصال قد يكون ضعيفًا) - عملية حسابية غير متزامنة معيّنة تستغرق أكثر من 30 ثانية
لإطالة مدة صلاحية الخدمة في هذه الحالات، يمكنك استدعاء واجهة برمجة تطبيقات بسيطة للإضافة بشكل دوري لإعادة ضبط عداد المهلة. يُرجى العِلم أنّ هذا الإجراء مخصّص للحالات الاستثنائية فقط، وفي معظم الحالات، تتوفّر عادةً طريقة أفضل وأكثر ملاءمةً للمنصة لتحقيق النتيجة نفسها.
يوضّح المثال التالي دالة مساعدة waitUntil()
تحافظ على تشغيل عامل الخدمة إلى أن يتم حلّ وعد معيّن:
async function waitUntil(promise) = {
const keepAlive = setInterval(chrome.runtime.getPlatformInfo, 25 * 1000);
try {
await promise;
} finally {
clearInterval(keepAlive);
}
}
waitUntil(someExpensiveCalculation());
إبقاء عامل الخدمة نشطًا باستمرار
في حالات نادرة، يكون من الضروري تمديد مدة الصلاحية إلى أجل غير مسمى. لقد حدّدنا المؤسسات والتعليم على أنّهما أكبر حالات الاستخدام، ونسمح بذلك فيهما على وجه التحديد، ولكن لا نوفّر هذه الميزة بشكل عام. في هذه الظروف الاستثنائية، يمكن الحفاظ على تشغيل عامل الخدمة من خلال استدعاء واجهة برمجة تطبيقات بسيطة لإضافة. من المهمّ ملاحظة أنّ هذا الاقتراح لا ينطبق إلا على الإضافات التي تعمل على الأجهزة المُدارة لحالات الاستخدام في المؤسسات أو المؤسسات التعليمية. ولا يُسمح بذلك في الحالات الأخرى، ويحتفظ فريق إضافات Chrome بالحق في اتّخاذ إجراء ضد هذه الإضافات في المستقبل.
استخدِم مقتطف الرمز التالي للحفاظ على تشغيل worker الخدمة:
/**
* Tracks when a service worker was last alive and extends the service worker
* lifetime by writing the current time to extension storage every 20 seconds.
* You should still prepare for unexpected termination - for example, if the
* extension process crashes or your extension is manually stopped at
* chrome://serviceworker-internals.
*/
let heartbeatInterval;
async function runHeartbeat() {
await chrome.storage.local.set({ 'last-heartbeat': new Date().getTime() });
}
/**
* Starts the heartbeat interval which keeps the service worker alive. Call
* this sparingly when you are doing work which requires persistence, and call
* stopHeartbeat once that work is complete.
*/
async function startHeartbeat() {
// Run the heartbeat once at service worker startup.
runHeartbeat().then(() => {
// Then again every 20 seconds.
heartbeatInterval = setInterval(runHeartbeat, 20 * 1000);
});
}
async function stopHeartbeat() {
clearInterval(heartbeatInterval);
}
/**
* Returns the last heartbeat stored in extension storage, or undefined if
* the heartbeat has never run before.
*/
async function getLastHeartbeat() {
return (await chrome.storage.local.get('last-heartbeat'))['last-heartbeat'];
}