सर्विस वर्कर पर माइग्रेट करें

बैकग्राउंड या इवेंट पेजों को सर्विस वर्कर से बदलना

सर्विस वर्कर, एक्सटेंशन के बैकग्राउंड या इवेंट पेज की जगह ले लेता है, ताकि बैकग्राउंड कोड मुख्य थ्रेड से दूर रहे. इससे, एक्सटेंशन सिर्फ़ तब चल पाते हैं, जब उनकी ज़रूरत होती है. इससे संसाधनों की बचत होती है.

एक्सटेंशन के लॉन्च होने से ही, बैकग्राउंड पेज उनके लिए एक ज़रूरी कॉम्पोनेंट रहे हैं. आसान शब्दों में कहें, तो बैकग्राउंड पेज ऐसा प्लैटफ़ॉर्म उपलब्ध कराते हैं जो किसी भी अन्य विंडो या टैब से अलग होता है. इससे एक्सटेंशन, इवेंट को मॉनिटर कर सकते हैं और उनके हिसाब से कार्रवाई कर सकते हैं.

इस पेज पर, बैकग्राउंड पेजों को एक्सटेंशन सेवा वर्कर्स में बदलने के टास्क के बारे में बताया गया है. एक्सटेंशन के लिए सर्विस वर्कर के बारे में ज़्यादा जानने के लिए, सर्विस वर्कर की मदद से इवेंट मैनेज करना ट्यूटोरियल और एक्सटेंशन के लिए सर्विस वर्कर के बारे में जानकारी सेक्शन देखें.

बैकग्राउंड स्क्रिप्ट और एक्सटेंशन सेवा वर्कर्स के बीच अंतर

कुछ संदर्भों में, आपको एक्सटेंशन सेवा वर्कर्स 'बैकग्राउंड स्क्रिप्ट' के तौर पर दिखेंगे. एक्सटेंशन सर्विस वर्कर, बैकग्राउंड में चलते हैं. हालांकि, उन्हें बैकग्राउंड स्क्रिप्ट कहना कुछ भ्रमित करने वाला है. ऐसा इसलिए, क्योंकि इससे यह लगता है कि इनकी सुविधाएं एक जैसी हैं. अंतर नीचे दिए गए हैं.

बैकग्राउंड पेजों में हुए बदलाव

बैकग्राउंड पेजों की तुलना में, सेवा वर्कर में कई अंतर होते हैं.

  • ये मुख्य थ्रेड के बाहर काम करते हैं. इसका मतलब है कि ये एक्सटेंशन के कॉन्टेंट में कोई रुकावट नहीं डालते.
  • इनमें कुछ खास सुविधाएं होती हैं, जैसे कि एक्सटेंशन के ऑरिजिन पर, फ़ेच इवेंट को इंटरसेप्ट करना. उदाहरण के लिए, टूलबार पॉप-अप से इवेंट रोकना.
  • वे क्लाइंट इंटरफ़ेस की मदद से, दूसरे कॉन्टेक्स्ट के साथ बातचीत और इंटरैक्ट कर सकते हैं.

आपको जो बदलाव करने होंगे

बैकग्राउंड स्क्रिप्ट और सेवा वर्कर के काम करने के तरीके में अंतर के हिसाब से, आपको कोड में कुछ बदलाव करने होंगे. सबसे पहले, मेनिफ़ेस्ट फ़ाइल में सर्विस वर्कर के बारे में बताने का तरीका, बैकग्राउंड स्क्रिप्ट के बारे में बताने के तरीके से अलग है. इसके अलावा:

  • ये कॉल, डीओएम या window इंटरफ़ेस को ऐक्सेस नहीं कर सकते. इसलिए, आपको ऐसे कॉल को किसी दूसरे एपीआई या ऑफ़स्क्रीन दस्तावेज़ में ले जाना होगा.
  • इवेंट के कॉलबैक में या रिटर्न किए गए प्रॉमिस के जवाब में, इवेंट लिसनर रजिस्टर नहीं किए जाने चाहिए.
  • ये XMLHttpRequest() के साथ काम नहीं करते. इसलिए, आपको इस इंटरफ़ेस के कॉल को fetch() के कॉल से बदलना होगा.
  • इस्तेमाल में न होने पर ये वैरिएबल बंद हो जाते हैं. इसलिए, आपको ग्लोबल वैरिएबल के बजाय, ऐप्लिकेशन की स्थितियों को सेव करके रखना होगा. सेवा वर्कर को बंद करने पर, टाइमर भी समय पूरा होने से पहले खत्म हो सकते हैं. आपको उन्हें अलार्म से बदलना होगा.

इस पेज पर इन टास्क के बारे में पूरी जानकारी दी गई है.

मेनिफ़ेस्ट में "background" फ़ील्ड को अपडेट करना

मेनिफ़ेस्ट V3 में, बैकग्राउंड पेजों की जगह सर्विस वर्कर ले लेता है. मेनिफ़ेस्ट में हुए बदलावों की सूची यहां दी गई है.

  • manifest.json में "background.scripts" को "background.service_worker" से बदलें. ध्यान दें कि "service_worker" फ़ील्ड में स्ट्रिंग डाली जाती है, न कि स्ट्रिंग का कलेक्शन.
  • manifest.json से "background.persistent" को हटाएं.
मेनिफ़ेस्ट V2
{
  ...
  "background": {
    "scripts": [
      "backgroundContextMenus.js",
      "backgroundOauth.js"
    ],
    "persistent": false
  },
  ...
}
मेनिफ़ेस्ट V3
{
  ...
  "background": {
    "service_worker": "service_worker.js",
    "type": "module"
  }
  ...
}

"service_worker" फ़ील्ड में सिर्फ़ एक स्ट्रिंग डाली जा सकती है. "type" फ़ील्ड का इस्तेमाल सिर्फ़ तब करना होगा, जब ES मॉड्यूल (import कीवर्ड का इस्तेमाल करके) का इस्तेमाल किया जा रहा हो. इसकी वैल्यू हमेशा "module" होगी. ज़्यादा जानकारी के लिए, एक्सटेंशन सेवा वर्कर के बारे में बुनियादी जानकारी देखें

डीओएम और विंडो कॉल को ऑफ़स्क्रीन दस्तावेज़ पर ले जाना

कुछ एक्सटेंशन को नई विंडो या टैब खोले बिना, 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 में पहले सेव किए गए डेटा को किसी दूसरे तरीके पर माइग्रेट करने के लिए:

  1. कन्वर्ज़न रूटीन और runtime.onMessage हैंडलर के साथ ऑफ़स्क्रीन दस्तावेज़ बनाएं.
  2. ऑफ़स्क्रीन दस्तावेज़ में कन्वर्ज़न रूटीन जोड़ें.
  3. एक्सटेंशन सर्विस वर्कर में जाकर, अपना डेटा देखने के लिए, chrome.storage को चुनें.
  4. अगर आपको अपना डेटा नहीं मिलता है, तो ऑफ़स्क्रीन दस्तावेज़ create और कन्वर्ज़न रूटीन शुरू करने के लिए, runtime.sendMessage() को कॉल करें.
  5. ऑफ़स्क्रीन दस्तावेज़ में जोड़े गए runtime.onMessage हैंडलर में, कन्वर्ज़न रूटीन को कॉल करें.

एक्सटेंशन में वेब स्टोरेज एपीआई के काम करने के तरीके में भी कुछ बारीकियां हैं. ज़्यादा जानने के लिए, स्टोरेज और कुकी लेख पढ़ें.

लिसनर को सिंक करके रजिस्टर करना

किसी लिसनर को एसिंक्रोनस तरीके से रजिस्टर करने की कोई गारंटी नहीं है. उदाहरण के लिए, प्रॉमिस या कॉलबैक में, मेनिफ़ेस्ट V3 में काम करने की गारंटी नहीं है. नीचे दिया गया कोड देखें.

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.browserAction.setBadgeText({ text: badgeText });
  chrome.browserAction.onClicked.addListener(handleActionClick);
});

यह सुविधा, बैकग्राउंड में लगातार चलने वाले पेज के साथ काम करती है, क्योंकि यह पेज लगातार चलता रहता है और इसे कभी भी फिर से शुरू नहीं किया जाता. मेनिफ़ेस्ट V3 में, इवेंट डिस्पैच होने पर सेवा वर्कर को फिर से शुरू किया जाएगा. इसका मतलब है कि इवेंट के ट्रिगर होने पर, लिसनर को रजिस्टर नहीं किया जाएगा. ऐसा इसलिए, क्योंकि उन्हें एसिंक्रोनस तरीके से जोड़ा जाता है. साथ ही, इवेंट को रिकॉर्ड नहीं किया जाता.

इसके बजाय, इवेंट लिसनर रजिस्ट्रेशन को अपनी स्क्रिप्ट के टॉप लेवल पर ले जाएं. इससे यह पक्का होता है कि Chrome, आपकी कार्रवाई के क्लिक हैंडलर को तुरंत ढूंढ और उसे ट्रिगर कर पाएगा. भले ही, आपका एक्सटेंशन स्टार्टअप लॉजिक को लागू करना पूरा न कर पाया हो.

chrome.action.onClicked.addListener(handleActionClick);

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.action.setBadgeText({ text: badgeText });
});

XMLHttpRequest() को global fetch() से बदलें

XMLHttpRequest() को किसी सेवा वर्कर, एक्सटेंशन या किसी अन्य तरीके से कॉल नहीं किया जा सकता. अपनी बैकग्राउंड स्क्रिप्ट के कॉल को XMLHttpRequest() में ग्लोबल fetch() के कॉल से बदलें.

XMLHttpRequest()
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);

सेटिंग को सेव करना

सेवा वर्कर कुछ समय के लिए काम करते हैं. इसका मतलब है कि उपयोगकर्ता के ब्राउज़र सेशन के दौरान, वे बार-बार शुरू, चलेंगे, और बंद हो जाएंगे. इसका मतलब यह भी है कि पिछला कॉन्टेक्स्ट हटा दिया गया था, इसलिए ग्लोबल वैरिएबल में डेटा तुरंत उपलब्ध नहीं होता. इस समस्या से बचने के लिए, स्टोरेज एपीआई का इस्तेमाल सटीक जानकारी के सोर्स के तौर पर करें. इसका तरीका जानने के लिए, यहां दिया गया उदाहरण देखें.

नीचे दिए गए उदाहरण में, नाम को स्टोर करने के लिए ग्लोबल वैरिएबल का इस्तेमाल किया गया है. सर्विस वर्कर में, यह वैरिएबल उपयोगकर्ता के ब्राउज़र सेशन के दौरान कई बार रीसेट किया जा सकता है.

मेनिफ़ेस्ट V2 की बैकग्राउंड स्क्रिप्ट
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 });
});

मेनिफ़ेस्ट V3 के लिए, ग्लोबल वैरिएबल को Storage API के कॉल से बदलें.

मेनिफ़ेस्ट V3 सर्विस वर्कर
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() तरीकों का इस्तेमाल करके, देर से या समय-समय पर होने वाली कार्रवाइयों का इस्तेमाल करना आम बात है. हालांकि, ये एपीआई सर्विस वर्कर में काम नहीं कर सकते, क्योंकि जब भी सर्विस वर्कर को बंद किया जाता है, तो टाइमर रद्द हो जाते हैं.

मेनिफ़ेस्ट V2 की बैकग्राउंड स्क्रिप्ट
// 3 minutes in milliseconds
const TIMEOUT = 3 * 60 * 1000;
setTimeout(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
}, TIMEOUT);

इसके बजाय, Alarms API का इस्तेमाल करें. अन्य लिसनर की तरह, अलार्म लिसनर को भी आपकी स्क्रिप्ट के सबसे ऊपर वाले लेवल में रजिस्टर किया जाना चाहिए.

मेनिफ़ेस्ट V3 सर्विस वर्कर
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 एक्सटेंशन टीम भविष्य में उन एक्सटेंशन पर कार्रवाई करने का अधिकार सुरक्षित रखती है.

अपने सेवा वर्कर को चालू रखने के लिए, नीचे दिए गए कोड स्निपेट का इस्तेमाल करें:

/**
 * 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'];
}