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

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

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

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

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

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

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: ओएमटी की केस स्टडी

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

खास जानकारी

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

इसके अलावा, ओएमटी के ये फ़ायदे भी हैं:

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