सर्विस वर्कर की मदद से, बैकग्राउंड या इवेंट पेजों को बदलना
सर्विस वर्कर, एक्सटेंशन के बैकग्राउंड या इवेंट पेज को बदल देता है, ताकि यह पक्का किया जा सके कि बैकग्राउंड कोड, मुख्य थ्रेड से अलग रहे. इससे एक्सटेंशन सिर्फ़ तब चलते हैं, जब उनकी ज़रूरत होती है. इससे संसाधनों की बचत होती है.
बैकग्राउंड पेज, एक्सटेंशन के लॉन्च होने के बाद से ही उनका एक अहम हिस्सा रहे हैं. आसान शब्दों में कहें, तो बैकग्राउंड पेज एक ऐसा एनवायरमेंट उपलब्ध कराते हैं जो किसी अन्य विंडो या टैब से अलग होता है. इससे एक्सटेंशन को इवेंट देखने और उनके हिसाब से कार्रवाई करने की अनुमति मिलती है.
इस पेज पर, बैकग्राउंड पेजों को एक्सटेंशन सर्विस वर्कर में बदलने से जुड़े टास्क के बारे में बताया गया है. एक्सटेंशन सर्विस वर्कर के बारे में ज़्यादा जानने के लिए, सर्विस वर्कर की मदद से इवेंट मैनेज करना ट्यूटोरियल और एक्सटेंशन सर्विस वर्कर के बारे में जानकारी सेक्शन देखें.
बैकग्राउंड स्क्रिप्ट और एक्सटेंशन सर्विस वर्कर के बीच अंतर
कुछ मामलों में, आपको एक्सटेंशन के सर्विस वर्कर दिखेंगे. इन्हें 'बैकग्राउंड स्क्रिप्ट' कहा जाता है. एक्सटेंशन के सर्विस वर्कर, बैकग्राउंड में काम करते हैं. हालांकि, उन्हें बैकग्राउंड स्क्रिप्ट कहना कुछ हद तक गुमराह करने वाला है. ऐसा इसलिए, क्योंकि इससे यह पता चलता है कि दोनों की क्षमताएं एक जैसी हैं. इन दोनों के बीच के फ़र्क़ यहां बताए गए हैं.
बैकग्राउंड पेजों में हुए बदलाव
सर्विस वर्कर और बैकग्राउंड पेजों में कई अंतर होते हैं.
- ये मुख्य थ्रेड से अलग काम करते हैं. इसका मतलब है कि ये एक्सटेंशन के कॉन्टेंट में कोई रुकावट नहीं डालते.
- इनके पास कुछ खास क्षमताएं होती हैं. जैसे, एक्सटेंशन के ऑरिजिन पर फ़ेच इवेंट को इंटरसेप्ट करना. जैसे, टूलबार पॉप-अप से मिलने वाले इवेंट.
- वे क्लाइंट इंटरफ़ेस के ज़रिए, अन्य कॉन्टेक्स्ट के साथ कम्यूनिकेट और इंटरैक्ट कर सकते हैं.
आपको ये बदलाव करने होंगे
बैकग्राउंड स्क्रिप्ट और सर्विस वर्कर के काम करने के तरीके में अंतर होता है. इसलिए, आपको कोड में कुछ बदलाव करने होंगे. सबसे पहले, मेनिफ़ेस्ट फ़ाइल में सर्विस वर्कर को बताने का तरीका, बैकग्राउंड स्क्रिप्ट को बताने के तरीके से अलग होता है. इसके अलावा:
- इनके पास DOM या
windowइंटरफ़ेस का ऐक्सेस नहीं होता. इसलिए, आपको ऐसे कॉल को किसी दूसरे एपीआई या ऑफ़स्क्रीन दस्तावेज़ में ले जाना होगा. - इवेंट लिसनर को, पूरे किए गए वादों के जवाब में या इवेंट कॉलबैक के अंदर रजिस्टर नहीं किया जाना चाहिए.
- ये
XMLHttpRequest()के साथ काम नहीं करते हैं. इसलिए, आपको इस इंटरफ़ेस पर किए गए कॉल कोfetch()पर किए गए कॉल से बदलना होगा. - इनका इस्तेमाल न होने पर, ये बंद हो जाते हैं. इसलिए, आपको ग्लोबल वैरिएबल पर भरोसा करने के बजाय, ऐप्लिकेशन की स्थितियों को बनाए रखना होगा. सर्विस वर्कर को बंद करने से, टाइमर के पूरा होने से पहले ही उन्हें बंद किया जा सकता है. आपको उन्हें अलार्म से बदलना होगा.
इस पेज पर इन टास्क के बारे में ज़्यादा जानकारी दी गई है.
मेनिफ़ेस्ट में "background" फ़ील्ड को अपडेट करें
Manifest V3 में, बैकग्राउंड पेजों की जगह सर्विस वर्कर का इस्तेमाल किया जाता है. मेनिफ़ेस्ट में हुए बदलावों के बारे में यहां बताया गया है.
manifest.jsonमें"background.scripts"को"background.service_worker"से बदलें. ध्यान दें कि"service_worker"फ़ील्ड में स्ट्रिंग का इस्तेमाल किया जाता है, न कि स्ट्रिंग के कलेक्शन का.manifest.jsonसे"background.persistent"को हटाएं.
{ ... "background": { "scripts": [ "backgroundContextMenus.js", "backgroundOauth.js" ], "persistent": false }, ... }
{ ... "background": { "service_worker": "service_worker.js", "type": "module" } ... }
"service_worker" फ़ील्ड में सिर्फ़ एक स्ट्रिंग होती है. अगर import कीवर्ड का इस्तेमाल करके ES मॉड्यूल का इस्तेमाल किया जाता है, तो आपको सिर्फ़ "type" फ़ील्ड की ज़रूरत होगी. इसकी वैल्यू हमेशा "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.storageको चुनें. - अगर आपका डेटा नहीं मिलता है, तो ऑफ़स्क्रीन दस्तावेज़ बनाएं और कन्वर्ज़न रूटीन शुरू करने के लिए,
runtime.sendMessage()को कॉल करें. - आपने ऑफ़स्क्रीन दस्तावेज़ में जो
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() को कॉल करने के बजाय global 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);
स्थितियों को बनाए रखना
सर्विस वर्कर कुछ समय के लिए होते हैं. इसका मतलब है कि उपयोगकर्ता के ब्राउज़र सेशन के दौरान, ये बार-बार शुरू, बंद, और खत्म होते रहेंगे. इसका यह भी मतलब है कि पिछले कॉन्टेक्स्ट को हटा दिए जाने की वजह से, ग्लोबल वैरिएबल में डेटा तुरंत उपलब्ध नहीं होता. इससे बचने के लिए, स्टोरेज एपीआई को सोर्स ऑफ़ ट्रुथ के तौर पर इस्तेमाल करें. उदाहरण में बताया गया है कि ऐसा कैसे किया जाता है.
इस उदाहरण में, नाम को सेव करने के लिए ग्लोबल वैरिएबल का इस्तेमाल किया गया है. सर्विस वर्कर में, उपयोगकर्ता के ब्राउज़र सेशन के दौरान इस वैरिएबल को कई बार रीसेट किया जा सकता है.
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 के कॉल से बदलें.
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 एक्सटेंशन टीम के पास यह अधिकार है कि वह आने वाले समय में ऐसे एक्सटेंशन के ख़िलाफ़ कार्रवाई करे.
अपने सर्विस वर्कर को चालू रखने के लिए, इस कोड स्निपेट का इस्तेमाल करें:
/**
* 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'];
}