ब्राउज़र के मुख्य थ्रेड से JavaScript चलाने के लिए वेब वर्कर का इस्तेमाल करें

मुख्य थ्रेड के अलावा किसी अन्य आर्किटेक्चर से, आपके ऐप्लिकेशन का भरोसा और उपयोगकर्ता अनुभव काफ़ी बेहतर हो सकता है.

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

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

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

वेब वर्कर्स क्यों इस्तेमाल करें?

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

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

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

वेब कर्मियों के साथ थ्रेड करना

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

JavaScript में, वेब वर्कर्स की मदद से भी कुछ हद तक ऐसी ही सुविधाएं मिल सकती हैं. वेब वर्कर्स की सुविधा 2007 से उपलब्ध है और 2012 से सभी मुख्य ब्राउज़र पर काम करती है. वेब वर्कर्स, मुख्य थ्रेड के साथ-साथ चलते हैं. हालांकि, ओएस थ्रेडिंग के उलट, वे वैरिएबल शेयर नहीं कर सकते.

वेब वर्कर्स बनाने के लिए, वर्कर्स कन्स्ट्रक्टर को कोई फ़ाइल पास करें. यह फ़ाइल, एक अलग थ्रेड में चलने लगती है:

const worker = new Worker("./worker.js");

postMessage एपीआई का इस्तेमाल करके मैसेज भेजकर, वेब वर्कर्स से संपर्क करें. postMessage कॉल में मैसेज की वैल्यू को पैरामीटर के तौर पर पास करें. इसके बाद, वर्कर्स में मैसेज इवेंट के लिए, इवेंट सुनने वाला जोड़ें:

main.js

const worker = new Worker('./worker.js');
worker.postMessage([40, 2]);

worker.js

addEventListener('message', event => {
  const [a, b] = event.data;

  // Do stuff with the message
  // ...
});

मुख्य थ्रेड पर मैसेज भेजने के लिए, वेब वर्कर्स में उसी postMessage एपीआई का इस्तेमाल करें और मुख्य थ्रेड पर इवेंट लिसनर सेट अप करें:

main.js

const worker = new Worker('./worker.js');

worker.postMessage([40, 2]);
worker.addEventListener('message', event => {
  console.log(event.data);
});

worker.js

addEventListener('message', event => {
  const [a, b] = event.data;

  // Do stuff with the message
  postMessage(a + b);
});

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

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

Comlink एक लाइब्रेरी है. इसका मकसद, आपको postMessage की जानकारी के बारे में सोचे बिना वेब वर्कर्स का इस्तेमाल करने की सुविधा देना है. Comlink की मदद से आप वेब वर्कर और मुख्य थ्रेड के बीच वैरिएबल शेयर कर सकते हैं. यह ठीक उन सभी प्रोग्रामिंग भाषाओं की तरह है जो थ्रेडिंग के साथ काम करते हैं.

Comlink को वेब वर्कर्स में इंपोर्ट करके और मुख्य थ्रेड को दिखाने के लिए फ़ंक्शन का एक सेट तय करके सेट अप किया जाता है. इसके बाद, मुख्य थ्रेड पर Comlink इंपोर्ट करें, वर्कर को रैप करें, और बिना अनुमति के सार्वजनिक किए गए फ़ंक्शन का ऐक्सेस पाएं:

worker.js

import {expose} from 'comlink';

const api = {
  someMethod() {
    // ...
  }
}

expose(api);

main.js

import {wrap} from 'comlink';

const worker = new Worker('./worker.js');
const api = wrap(worker);

मुख्य थ्रेड पर मौजूद api वैरिएबल, वेब वर्कर्स में मौजूद वैरिएबल की तरह ही काम करता है. हालांकि, हर फ़ंक्शन में वैल्यू के बजाय, एक प्रॉमिस रिटर्न किया जाता है.

आपको किसी वेब वर्कर पर कौनसा कोड भेजना चाहिए?

वेब वर्कर्स के पास डीओएम और WebUSB, WebRTC या Web Audio जैसे कई एपीआई का ऐक्सेस नहीं होता. इसलिए, अपने ऐप्लिकेशन के ऐसे हिस्सों को वर्कर्स में नहीं डाला जा सकता जो इस तरह के ऐक्सेस पर निर्भर होते हैं. इसके बावजूद, वर्कर्स पर भेजे गए कोड के हर छोटे हिस्से से, मुख्य थ्रेड में ज़्यादा जगह मिलती है. इस जगह का इस्तेमाल, यूज़र इंटरफ़ेस को अपडेट करने जैसे कामों के लिए किया जाता है.

वेब डेवलपर के लिए एक समस्या यह है कि ज़्यादातर वेब ऐप्लिकेशन, ऐप्लिकेशन में हर चीज़ को व्यवस्थित करने के लिए, Vue या React जैसे यूज़र इंटरफ़ेस (यूआई) फ़्रेमवर्क का इस्तेमाल करते हैं. हर चीज़ फ़्रेमवर्क का कॉम्पोनेंट होता है और इसलिए वह डीओएम से पहले से ही जुड़ा होता है. ऐसा करने से, OMT आर्किटेक्चर पर माइग्रेट करना मुश्किल हो जाएगा.

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

PROXX: OMT की एक केस स्टडी

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

टीम ने गेम के विज़ुअल स्टेटस को उसके लॉजिक से अलग करने के लिए, वेब वर्कर्स का इस्तेमाल करने का फ़ैसला लिया:

  • मुख्य थ्रेड ऐनिमेशन की रेंडरिंग और ट्रांज़िशन को हैंडल करती है.
  • वेब वर्कर, गेम लॉजिक को मैनेज करता है. यह पूरी तरह से कंप्यूटेशनल होता है.

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

PROXX के बिना OMT वाले वर्शन में यूज़र इंटरफ़ेस (यूआई) के रिस्पॉन्स में लगने वाला समय.

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

PROXX के OMT वर्शन में यूज़र इंटरफ़ेस (यूआई) के रिस्पॉन्स का समय.

ऐसा सोच-समझकर किया जाना चाहिए: हम सीमित सुविधाओं वाले डिवाइसों का इस्तेमाल करने वाले लोगों को बेहतर अनुभव देते हैं. इससे, बेहतर डिवाइसों के उपयोगकर्ताओं पर जुर्माना नहीं लगता और उन्हें बेहतर अनुभव मिलता है.

OMT आर्किटेक्चर के असर

PROXX के उदाहरण से पता चलता है कि OMT की मदद से, आपका ऐप्लिकेशन ज़्यादा डिवाइसों पर भरोसेमंद तरीके से चलता है. हालांकि, इससे आपका ऐप्लिकेशन तेज़ी से नहीं चलता:

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

फ़ायदे और नुकसान को ध्यान में रखें

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

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

टूल के बारे में जानकारी

वेब वर्कर्स अभी तक मुख्य तौर पर इस्तेमाल नहीं किए जा रहे हैं. इसलिए, webpack और Rollup जैसे ज़्यादातर मॉड्यूल टूल, बिना किसी बदलाव के इनका इस्तेमाल नहीं कर सकते. (हालांकि, पार्सल काम करता है!) अच्छी बात यह है कि वेब वर्कर्स को वेबपैक और रोलअप के साथ काम करने के लिए, प्लग इन उपलब्ध हैं:

खास जानकारी

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

साथ ही, OMT के ये अन्य फ़ायदे भी हैं:

  • यह JavaScript को लागू करने की लागत को एक अलग थ्रेड में ले जाता है.
  • इससे पार्स करने की लागत कम हो जाती है. इसका मतलब है कि यूज़र इंटरफ़ेस (यूआई) तेज़ी से बूट हो सकता है. इससे First Contentful Paint या Time to Interactive हो सकता है, जिससे आपका Lighthouse स्कोर बढ़ सकता है.

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