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

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

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

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

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

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

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

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

सर्विस वर्कर के बैकग्राउंड पेजों में कई अंतर होते हैं.

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

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

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

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

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

मेनिफ़ेस्ट में "बैकग्राउंड" फ़ील्ड अपडेट करें

मेनिफ़ेस्ट 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" फ़ील्ड में एक स्ट्रिंग होती है. अगर ES मॉड्यूल (import कीवर्ड का इस्तेमाल करके) का इस्तेमाल किया जाता है, तो आपको सिर्फ़ "type" फ़ील्ड की ज़रूरत होगी. इसकी वैल्यू हमेशा "module" होगी. ज़्यादा जानकारी के लिए, एक्सटेंशन सर्विस वर्कर की बुनियादी बातें देखें

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

कुछ एक्सटेंशन को नई विंडो या टैब को विज़ुअल तौर पर खोले बिना ही, डीओएम और विंडो ऑब्जेक्ट का ऐक्सेस चाहिए. 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. अगर आपका डेटा नहीं मिलता है, तो एक ऑफ़स्क्रीन दस्तावेज़ बनाएं और कन्वर्ज़न रूटीन शुरू करने के लिए, 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() को ग्लोबल फ़ेच() से बदलें

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);
fetch()
const response = await fetch('https://www.example.com/greeting.json'')
console.log(response.statusText);

स्थायी स्थितियां

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

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

Manifest 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 पर कॉल से बदलें.

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

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

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

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