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

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

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

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

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

वेब वर्कर क्यों?

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

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

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

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

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

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

वेब वर्कर बनाने के लिए, वर्कर कंस्ट्रक्टर को एक फ़ाइल पास करें, जिससे उस फ़ाइल को एक अलग थ्रेड में चलाना शुरू हो जाएगा:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

कीमत में बदलाव करने से पहले सोचें

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

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

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

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

खास जानकारी

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

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

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

वेब कर्मियों को डरावना नहीं होना चाहिए. Comlink जैसे टूल कर्मचारियों से काम अलग से ले रहे हैं और उन्हें वेब ऐप्लिकेशन की व्यापक श्रेणी के लिए एक व्यवहार्य विकल्प बना रहे हैं.

जेम्स पीकॉक की अनस्प्लैश की हीरो इमेज.