प्रोडक्शन में सर्विस वर्कर

पोर्ट्रेट स्क्रीनशॉट

खास जानकारी

जानें कि हमने Google I/O 2015 वेब ऐप्लिकेशन को तेज़ और ऑफ़लाइन-पहले बनाने के लिए किस तरह सर्विस वर्कर लाइब्रेरी का इस्तेमाल किया.

खास जानकारी

इस साल के Google I/O 2015 वेब ऐप्लिकेशन को, Google की डेवलपर रिलेशनशिप टीम ने लिखा है. इसे Instrument में काम करने वाले हमारे दोस्तों के डिज़ाइन के आधार पर बनाया गया है. उन्होंने ही ऑडियो/विज़ुअल एक्सपेरिमेंट को लिखा है. हमारी टीम का मकसद यह पक्का करना था कि I/O वेब ऐप्लिकेशन (जिसे मैं इसके कोडनेम, IOWA के नाम में बताऊं) के ज़रिए आधुनिक वेब की हर सुविधा दिखाएं. ज़रूरी सुविधाओं की हमारी सूची में, सबसे पहले ऑफ़लाइन अनुभव देने की सुविधा मौजूद थी.

अगर आपने हाल ही में इस साइट पर कोई दूसरा लेख पढ़ा है, तो आपको सेवा वर्कर के बारे में पता चला होगा. आपको यह जानकर हैरानी नहीं होगी कि IOWA की ऑफ़लाइन सहायता टीम का ज़्यादातर काम, इन पर निर्भर करता है. IOWA की ज़रूरतों को ध्यान में रखते हुए, हमने दो अलग-अलग ऑफ़लाइन इस्तेमाल के उदाहरणों को हैंडल करने के लिए दो लाइब्रेरी बनाई हैं: sw-precache, स्टैटिक रिसॉर्स को पहले से कैश मेमोरी में सेव करने की प्रोसेस को ऑटोमेट करने के लिए और sw-toolbox, रनटाइम कैश मेमोरी और फ़ॉलबैक की रणनीतियों को हैंडल करने के लिए.

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

sw-precache की मदद से, पहले से कैश मेमोरी में सेव किया जा रहा है

IOWA के स्थिर संसाधन—उसके HTML, JavaScript, CSS और चित्र—वेब ऐप्लिकेशन का मुख्य शेल प्रदान करते हैं. इन संसाधनों को कैश मेमोरी में सेव करने के लिए, दो खास शर्तें पूरी करना ज़रूरी था: हमें यह पक्का करना था कि ज़्यादातर स्टैटिक संसाधन कैश मेमोरी में सेव हों और उन्हें अप-टू-डेट रखा जाए. sw-precache को इन ज़रूरतों को ध्यान में रखकर बनाया गया है.

बिल्ड टाइम इंटिग्रेशन

sw-precache, IOWA की gulp पर आधारित बिल्ड प्रोसेस का इस्तेमाल करता है. साथ ही, हम glob पैटर्न की एक सीरीज़ पर भरोसा करते हैं, ताकि यह पक्का किया जा सके कि हम IOWA के इस्तेमाल किए जाने वाले सभी स्टैटिक रिसॉर्स की पूरी सूची जनरेट करें.

staticFileGlobs: [
    rootDir + '/bower_components/**/*.{html,js,css}',
    rootDir + '/elements/**',
    rootDir + '/fonts/**',
    rootDir + '/images/**',
    rootDir + '/scripts/**',
    rootDir + '/styles/**/*.css',
    rootDir + '/data-worker-scripts.js'
]

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

कैश मेमोरी में सेव किए गए रिसॉर्स अपडेट करना

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

जब कोई उपयोगकर्ता पहली बार IOWA पर जाता है, तो ग्लोब पैटर्न से मैच करने वाली हर फ़ाइल को डाउनलोड और कैश मेमोरी में सेव किया जाता है. हमने यह पक्का करने की कोशिश की है कि पेज को रेंडर करने के लिए ज़रूरी रिसोर्स ही पहले से कैश मेमोरी में सेव किए गए हों. ऑडियो/विज़ुअल एक्सपेरिमेंट में इस्तेमाल किए गए मीडिया या सेशन के स्पीकर की प्रोफ़ाइल इमेज जैसे सेकंडरी कॉन्टेंट को जान-बूझकर पहले से कैश मेमोरी में सेव नहीं किया गया था. इसके बजाय, हमने उन संसाधनों के लिए ऑफ़लाइन अनुरोधों को मैनेज करने के लिए, sw-toolbox लाइब्रेरी का इस्तेमाल किया था.

sw-toolbox, हमारी सभी डाइनैमिक ज़रूरतों के लिए

जैसा कि बताया गया है, किसी साइट को ऑफ़लाइन काम करने के लिए, हर संसाधन को पहले से कैश मेमोरी में सेव करना संभव नहीं है. कुछ संसाधन बहुत बड़े होते हैं या इनका इस्तेमाल कम किया जाता है. इसलिए, इनका इस्तेमाल करना फ़ायदेमंद नहीं होता. वहीं, कुछ संसाधन डाइनैमिक होते हैं. जैसे, किसी रिमोट एपीआई या सेवा से मिले जवाब. हालांकि, किसी अनुरोध को पहले से कैश मेमोरी में सेव न करने का मतलब यह नहीं है कि आपको NetworkError दिखेगा. sw-toolbox ने हमें अनुरोध हैंडलर लागू करने की सुविधा दी, जो कुछ संसाधनों के लिए रनटाइम कैश मेमोरी और दूसरों के लिए कस्टम फ़ॉलबैक मैनेज करते हैं. हमने पुश नोटिफ़िकेशन के रिस्पॉन्स में, कैश मेमोरी में सेव किए गए अपने पुराने संसाधनों को अपडेट करने में भी इसका इस्तेमाल किया.

यहां पसंद के मुताबिक बनाए गए अनुरोध हैंडलर के कुछ उदाहरण दिए गए हैं, जिन्हें हमने sw-toolbox के ऊपर बनाया है. sw-precache के importScripts parameter की मदद से, उन्हें बेस सर्विस वर्कर स्क्रिप्ट के साथ इंटिग्रेट करना आसान था. इसकी मदद से, स्टैंडअलोन JavaScript फ़ाइलें सर्विस वर्कर के स्कोप में आ जाती हैं.

ऑडियो/विज़ुअल एक्सपेरिमेंट

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

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

toolbox.router.get('/experiment/(.+)', toolbox.networkFirst);

स्पीकर की प्रोफ़ाइल की इमेज

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

var DEFAULT_PROFILE_IMAGE = 'images/touch/homescreen96.png';

function profileImageRequest(request) {
    return toolbox.cacheFirst(request).catch(function() {
    return toolbox.cacheOnly(new Request(DEFAULT_PROFILE_IMAGE));
    });
}

toolbox.precache([DEFAULT_PROFILE_IMAGE]);
toolbox.router.get('/(.+)/images/speakers/(.*)',
                    profileImageRequest,
                    {origin: /.*\.googleapis\.com/});
सेशन पेज पर मौजूद प्रोफ़ाइल इमेज
सेशन पेज की प्रोफ़ाइल इमेज.

उपयोगकर्ताओं के शेड्यूल में अपडेट

IOWA की एक अहम सुविधा यह थी कि साइन-इन कर चुके उपयोगकर्ताओं को उन सेशन का शेड्यूल बनाने और उसे बनाए रखने में मदद मिलती है जिनमें वे शामिल होने वाले थे. जैसा कि आपने अनुमान लगाया होगा, सेशन के अपडेट, बैकएंड सर्वर पर एचटीटीपी POST अनुरोधों के ज़रिए किए गए थे. साथ ही, हमने उपयोगकर्ता के ऑफ़लाइन होने पर, स्थिति में बदलाव करने वाले उन अनुरोधों को मैनेज करने का सबसे अच्छा तरीका ढूंढने में कुछ समय बिताया. हमने एक ऐसा तरीका अपनाया है जिसमें IndexedDB में, पूरे न हो पाने वाले अनुरोधों को कतार में लगाया जाता है. साथ ही, मुख्य वेब पेज में एक लॉजिक जोड़ा जाता है, जो IndexedDB में कतार में लगे अनुरोधों की जांच करता है और उनमें से किसी भी अनुरोध को फिर से आज़माता है.

var DB_NAME = 'shed-offline-session-updates';

function queueFailedSessionUpdateRequest(request) {
    simpleDB.open(DB_NAME).then(function(db) {
    db.set(request.url, request.method);
    });
}

function handleSessionUpdateRequest(request) {
    return global.fetch(request).then(function(response) {
    if (response.status >= 500) {
        return Response.error();
    }
    return response;
    }).catch(function() {
    queueFailedSessionUpdateRequest(request);
    });
}

toolbox.router.put('/(.+)api/v1/user/schedule/(.+)',
                    handleSessionUpdateRequest);
toolbox.router.delete('/(.+)api/v1/user/schedule/(.+)',
                        handleSessionUpdateRequest);

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

simpleDB.open(QUEUED_SESSION_UPDATES_DB_NAME).then(function(db) {
    var replayPromises = [];
    return db.forEach(function(url, method) {
    var promise = IOWA.Request.xhrPromise(method, url, true).then(function() {
        return db.delete(url).then(function() {
        return true;
        });
    });
    replayPromises.push(promise);
    }).then(function() {
    if (replayPromises.length) {
        return Promise.all(replayPromises).then(function() {
        IOWA.Elements.Toast.showMessage(
            'My Schedule was updated with offline changes.');
        });
    }
    });
}).catch(function() {
    IOWA.Elements.Toast.showMessage(
    'Offline changes could not be applied to My Schedule.');
});

ऑफ़लाइन Google Analytics

इसी तरह, हमने Google Analytics के ऐसे अनुरोधों को कतार में लगाने के लिए एक हैंडलर लागू किया है जो पूरे नहीं हो पाए. साथ ही, हमने उन अनुरोधों को बाद में फिर से चलाने की कोशिश की, जब नेटवर्क उपलब्ध था. इस तरीके से, ऑफ़लाइन होने का मतलब यह नहीं है कि आपको Google Analytics से मिलने वाली अहम जानकारी नहीं मिलेगी. हमने सूची में मौजूद हर अनुरोध में qt पैरामीटर जोड़ा है. यह पैरामीटर, अनुरोध करने के बाद से अब तक बीते समय पर सेट होता है. इससे यह पक्का किया जा सकता है कि Google Analytics के बैकएंड में सही इवेंट एट्रिब्यूशन समय शामिल हो. Google Analytics, qt के लिए सिर्फ़ चार घंटे तक की वैल्यू के साथ आधिकारिक तौर पर काम करता है. इसलिए, हमने हर बार जब भी सेवा वर्कर शुरू किया, तो उन अनुरोधों को जल्द से जल्द फिर से चलाने की पूरी कोशिश की.

var DB_NAME = 'offline-analytics';
var EXPIRATION_TIME_DELTA = 86400000;
var ORIGIN = /https?:\/\/((www|ssl)\.)?google-analytics\.com/;

function replayQueuedAnalyticsRequests() {
    simpleDB.open(DB_NAME).then(function(db) {
    db.forEach(function(url, originalTimestamp) {
        var timeDelta = Date.now() - originalTimestamp;
        var replayUrl = url + '&qt=' + timeDelta;
        fetch(replayUrl).then(function(response) {
        if (response.status >= 500) {
            return Response.error();
        }
        db.delete(url);
        }).catch(function(error) {
        if (timeDelta > EXPIRATION_TIME_DELTA) {
            db.delete(url);
        }
        });
    });
    });
}

function queueFailedAnalyticsRequest(request) {
    simpleDB.open(DB_NAME).then(function(db) {
    db.set(request.url, Date.now());
    });
}

function handleAnalyticsCollectionRequest(request) {
    return global.fetch(request).then(function(response) {
    if (response.status >= 500) {
        return Response.error();
    }
    return response;
    }).catch(function() {
    queueFailedAnalyticsRequest(request);
    });
}

toolbox.router.get('/collect',
                    handleAnalyticsCollectionRequest,
                    {origin: ORIGIN});
toolbox.router.get('/analytics.js',
                    toolbox.networkFirst,
                    {origin: ORIGIN});

replayQueuedAnalyticsRequests();

पुश नोटिफ़िकेशन के लैंडिंग पेज

सर्विस वर्कर सिर्फ़ IOWA की ऑफ़लाइन काम की क्षमता ही नहीं संभालते थे, बल्कि उन्होंने पुश नोटिफ़िकेशन को भी चालू किया होता था, जिनका इस्तेमाल हम उपयोगकर्ताओं को उनके बुकमार्क किए गए सेशन के अपडेट के बारे में सूचित करने के लिए करते थे. उन सूचनाओं से जुड़े लैंडिंग पेज पर, सेशन की अपडेट की गई जानकारी दिखती है. ये लैंडिंग पेज, पूरी साइट के हिस्से के तौर पर पहले से ही कैश मेमोरी में सेव किए जा रहे थे. इसलिए, ये पहले से ही ऑफ़लाइन काम कर रहे थे. हालांकि, हमें यह पक्का करना था कि उस पेज पर सेशन की जानकारी अप-टू-डेट हो, भले ही उसे ऑफ़लाइन देखा जा रहा हो. ऐसा करने के लिए, हमने पुश नोटिफ़िकेशन को ट्रिगर करने वाले अपडेट के साथ, पहले से कैश मेमोरी में सेव किए गए सेशन के मेटाडेटा में बदलाव किया. साथ ही, हमने नतीजे को कैश मेमोरी में सेव किया. सेशन की जानकारी वाला पेज अगली बार खोलने पर, अप-टू-डेट जानकारी का इस्तेमाल किया जाएगा. भले ही, इसे ऑनलाइन या ऑफ़लाइन खोला जाए.

caches.open(toolbox.options.cacheName).then(function(cache) {
    cache.match('api/v1/schedule').then(function(response) {
    if (response) {
        parseResponseJSON(response).then(function(schedule) {
        sessions.forEach(function(session) {
            schedule.sessions[session.id] = session;
        });
        cache.put('api/v1/schedule',
                    new Response(JSON.stringify(schedule)));
        });
    } else {
        toolbox.cache('api/v1/schedule');
    }
    });
});

ध्यान देने वाली बातें

बेशक, बिना किसी परेशानी के IOWA के बड़े प्रोजेक्ट पर कोई भी काम नहीं करता. यहां कुछ ऐसी समस्याओं के बारे में बताया गया है जिनका हमने सामना किया और उन्हें हल करने के तरीके के बारे में भी बताया गया है.

पुराना कॉन्टेंट

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

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

if (navigator.serviceWorker && navigator.serviceWorker.controller) {
    navigator.serviceWorker.controller.onstatechange = function(e) {
    if (e.target.state === 'redundant') {
        var tapHandler = function() {
        window.location.reload();
        };
        IOWA.Elements.Toast.showMessage(
        'Tap here or refresh the page for the latest content.',
        tapHandler);
    }
    };
}
नया कॉन्टेंट दिखाने वाला टॉस्ट
"नया कॉन्टेंट" टोस्ट.

पक्का करें कि स्टैटिक कॉन्टेंट स्टैटिक हो!

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

हमें I/O के दौरान इस व्यवहार से जुड़ी एक समस्या मिली. इसकी वजह यह है कि कॉन्फ़्रेंस के हर दिन के लिए, बैकएंड को YouTube वीडियो आईडी को डाइनैमिक तौर पर अपडेट करना पड़ रहा था. बुनियादी टेंप्लेट फ़ाइल स्टैटिक थी और उसमें कोई बदलाव नहीं हुआ था. इसलिए, हमारे सेवा वर्कर अपडेट फ़्लो को ट्रिगर नहीं किया गया. साथ ही, YouTube वीडियो अपडेट करने के लिए, सर्वर से मिलने वाला डाइनैमिक रिस्पॉन्स, कई उपयोगकर्ताओं के लिए कैश मेमोरी में सेव किया गया रिस्पॉन्स बन गया.

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

पहले से कैश मेमोरी में सेव करने के अनुरोधों को कैश-बस्ट करना

जब sw-precache, रिसॉर्स को पहले से कैश मेमोरी में सेव करने के लिए अनुरोध करता है, तो वह उन रिस्पॉन्स का इस्तेमाल तब तक करता है, जब तक उसे लगता है कि फ़ाइल का MD5 हैश नहीं बदला है. इसका मतलब है कि यह पक्का करना ज़रूरी है कि प्रीकैश करने के अनुरोध का रिस्पॉन्स नया हो, न कि ब्राउज़र के एचटीटीपी कैश मेमोरी से मिला हो. (हां, सर्विस वर्कर में किए गए fetch() अनुरोध, ब्राउज़र की एचटीटीपी कैश मेमोरी से डेटा का इस्तेमाल करके जवाब दे सकते हैं.)

यह पक्का करने के लिए कि हम जो जवाब पहले से कैश करते हैं वे सीधे नेटवर्क से आते हैं, न कि ब्राउज़र की एचटीटीपी कैश मेमोरी से, sw-precache अपने-आप अनुरोध किए गए हर यूआरएल में कैश मेमोरी को नुकसान पहुंचाने वाला क्वेरी पैरामीटर जोड़ देता है. अगर sw-precache का इस्तेमाल नहीं किया जा रहा है और कैश मेमोरी में डेटा सेव करके तुरंत जवाब देने की रणनीति का इस्तेमाल किया जा रहा है, तो पक्का करें कि आपने अपने कोड में कुछ ऐसा ही किया हो!

कैश मेमोरी को खत्म करने का एक बेहतर तरीका यह है कि पहले से कैश मेमोरी में सेव करने के लिए इस्तेमाल किए गए हर Request के कैश मेमोरी मोड को reload पर सेट किया जाए. इससे यह पक्का होगा कि रिस्पॉन्स नेटवर्क से आएगा. हालांकि, फ़िलहाल Chrome में कैश मेमोरी मोड का विकल्प काम नहीं करता.

साइन इन और साइन आउट करने के लिए सहायता

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

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

    self.addEventListener('message', function(event) {
      if (event.data === 'clear-cached-user-data') {
        caches.open(toolbox.options.cacheName).then(function(cache) {
          cache.keys().then(function(requests) {
            return requests.filter(function(request) {
              return request.url.indexOf('api/v1/user/') !== -1;
            });
          }).then(function(userDataRequests) {
            userDataRequests.forEach(function(userDataRequest) {
              cache.delete(userDataRequest);
            });
          });
        });
      }
    });

अतिरिक्त क्वेरी पैरामीटर से सावधान रहें!

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

इस वजह से, डेवलपमेंट के दौरान हमें समस्या का सामना करना पड़ा. हमने यूआरएल पैरामीटर का इस्तेमाल करना शुरू किया, ताकि यह पता लगाया जा सके कि ट्रैफ़िक कहां से आ रहा है. उदाहरण के लिए, हमने अपनी किसी सूचना पर क्लिक करने पर खुलने वाले यूआरएल में utm_source=notification पैरामीटर जोड़ा है. साथ ही, वेब ऐप्लिकेशन मेनिफ़ेस्ट के लिए, start_url में utm_source=web_app_manifest का इस्तेमाल किया है. पहले कैश मेमोरी में सेव किए गए रिस्पॉन्स से मैच करने वाले यूआरएल, उन पैरामीटर को जोड़ने पर, 'नहीं मिला' के तौर पर दिख रहे थे.

ignoreSearch विकल्प का इस्तेमाल करके, इस समस्या को कुछ हद तक हल किया जा सकता है.Cache.match() माफ़ करें, Chrome पर ignoreSearch का इस्तेमाल अभी तक नहीं किया जा सकता. भले ही, ऐसा किया जा सके, तब भी यह सुविधा या तो पूरी तरह से काम करेगी या बिलकुल नहीं करेगी. हमें कुछ यूआरएल क्वेरी पैरामीटर को अनदेखा करने के साथ-साथ, काम के अन्य पैरामीटर को ध्यान में रखने का तरीका चाहिए था.

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

function stripIgnoredUrlParameters(originalUrl, ignoredRegexes) {
    var url = new URL(originalUrl);

    url.search = url.search.slice(1)
    .split('&')
    .map(function(kv) {
        return kv.split('=');
    })
    .filter(function(kv) {
        return ignoredRegexes.every(function(ignoredRegex) {
        return !ignoredRegex.test(kv[0]);
        });
    })
    .map(function(kv) {
        return kv.join('=');
    })
    .join('&');

    return url.toString();
}

आपके लिए इसका क्या मतलब है

Google I/O वेब ऐप्लिकेशन में, सेवा वर्कर इंटिग्रेशन का इस्तेमाल करना सबसे मुश्किल है. ऐसा इसलिए है, क्योंकि इसे असल दुनिया में इस्तेमाल करने के लिए, अब तक सबसे ज़्यादा जटिल तरीके का इस्तेमाल किया गया है. हम वेब डेवलपर कम्यूनिटी के लिए, sw-precache और sw-toolbox जैसे टूल उपलब्ध कराने के साथ-साथ, वेब ऐप्लिकेशन बनाने के लिए नई तकनीकें बताने को लेकर उत्साहित हैं. सर्विस वर्कर एक प्रगतिशील सुविधा है, जिसका इस्तेमाल आज से किया जा सकता है. सही तरीके से बनाए गए वेब ऐप्लिकेशन के हिस्से के तौर पर इसका इस्तेमाल करने पर, आपके उपयोगकर्ताओं को तेज़ी और ऑफ़लाइन काम करने की सुविधा मिलती है.