सभी एपीआई में उपयोगकर्ता की गतिविधि को एक जैसा बनाना

Mustaq Ahmed
Joe Medley
Joe Medley

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

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

वर्शन 72 में, Chrome ने 'यूज़र ऐक्टिवेशन' वर्शन 2 भेजा है. इस वर्शन में, ऐक्टिवेशन से जुड़े सभी एपीआई के लिए, उपयोगकर्ता को ऐक्टिवेट करने की प्रोसेस पूरी हो जाती है. इससे ऊपर बताई गई गड़बड़ियां ठीक की जा सकती हैं. साथ ही, MessageChannels जैसी कुछ अन्य गड़बड़ियां ठीक की जा सकती हैं. हमारा मानना है कि इससे उपयोगकर्ता को ऐक्टिवेट करके वेब डेवलपमेंट में आसानी होगी. इसके अलावा, लागू किए गए नए बदलाव में, सुझाए गए नई जानकारी के लिए रेफ़रंस लागू करने की सुविधा मिलती है. इसका मकसद, लंबे समय में सभी ब्राउज़र को एक साथ लाना है.

उपयोगकर्ता ऐक्टिवेशन v2 कैसे काम करता है?

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

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

क्या बदलाव होने वाले हैं?

  • उपयोगकर्ता को ऐक्टिवेशन के लिए वर्शन 2, फ़्रेम की सीमाओं में उपयोगकर्ता की गतिविधि दिखाने के तरीके को औपचारिक बनाता है: किसी खास फ़्रेम के साथ उपयोगकर्ता के इंटरैक्शन पर, अब सभी शामिल फ़्रेम (और सिर्फ़ उन फ़्रेम) को चालू किया जाएगा, भले ही उनकी ऑरिजिन कुछ भी हो. (Chrome 72 में, हमारे पास कुछ समय के लिए एक समाधान है. इसकी मदद से, सभी फ़्रेम को एक ही ऑरिजिन से ऐक्सेस किया जा सकता है. जब हमें उपयोगकर्ता के लिए, सब-फ़्रेम सही तरीके से ऐक्टिवेट करने का तरीका मिल जाता है, तो हम इस समस्या को हटा देंगे.)
  • जब ऐक्टिवेशन-गेटेड एपीआई को किसी चालू फ़्रेम से कॉल किया जाता है, लेकिन किसी इवेंट हैंडलर कोड के बाहर से, यह तब तक काम करता है, जब तक कि उपयोगकर्ता को चालू करने की स्थिति "चालू" हो (उदाहरण के लिए, उसकी समयसीमा खत्म न हुई हो और न ही उसका इस्तेमाल किया गया हो). उपयोगकर्ता को ऐक्टिवेशन के वर्शन 2 से पहले, यह बिलकुल फ़ेल हो जाएगा.
  • समयसीमा खत्म होने के समय के अंतराल में, इस्तेमाल नहीं किए गए कई उपयोगकर्ता इंटरैक्शन, आखिरी इंटरैक्शन के हिसाब से एक ही बार में चालू हो जाते हैं.

ऐक्टिवेशन-गेटेड एपीआई में एक जैसे होने के उदाहरण

यहां पॉप-अप विंडो (window.open() का इस्तेमाल करके खोली गई) के दो उदाहरण दिए गए हैं. इनसे पता चलता है कि यूज़र ऐक्टिवेशन v2, ऐक्टिवेशन से सुरक्षित किए गए एपीआई के काम करने के तरीके को किस तरह एक जैसा बनाता है.

एक के बाद एक बनाए गए setTimeout() कॉल

यह उदाहरण हमारे setTimeout() डेमो से लिया गया है. अगर click हैंडलर एक सेकंड के अंदर पॉप-अप खोलने की कोशिश करता है, तो उसके काम करना आसान हो जाता है, भले ही कोड किसी भी तरह से देरी को "लिखता" हो. उपयोगकर्ता ऐक्टिवेशन v2 इस उम्मीद को पूरा करता है. इसलिए, नीचे दिया गया हर इवेंट हैंडलर click (100 मि॰से॰ की देरी के साथ) पर एक पॉप-अप खोलता है:

function popupAfter100ms() {
  setTimeout(callWindowOpen, 100);
}

function asyncPopupAfter100ms() {
  setTimeout(popupAfter100ms, 0);
}

someButton.addEventListener('click', popupAfter100ms);
someButton.addEventListener('click', asyncPopupAfter100ms);

उपयोगकर्ता ऐक्टिवेशन v2 के बिना, दूसरा इवेंट हैंडलर उन सभी ब्राउज़र में काम नहीं करता है जिनकी हमने जांच की है. (इनमें से पहला वाला भी फ़ेल हो जाता है कुछ मामलों में.)

क्रॉस-डोमेन postMessage() कॉल

यहां हमारे postMessage() डेमो का एक उदाहरण दिया गया है. मान लीजिए कि किसी क्रॉस-ऑरिजिन सबफ़्रेम में मौजूद click हैंडलर, पैरंट फ़्रेम पर सीधे दो मैसेज भेजता है. इनमें से कोई एक मैसेज मिलने पर, पैरंट फ़्रेम कोई पॉप-अप खोल पाएगा, लेकिन दोनों नहीं:

// Parent frame code
window.addEventListener('message', e => {
  if (e.data === 'open_popup' && e.origin === child_origin)
    window.open('about:blank');
});

// Child frame code:
someButton.addEventListener('click', () => {
  parent.postMessage('hi_there', parent_origin);
  parent.postMessage('open_popup', parent_origin);
});

यूज़र ऐक्टिवेशन v2 के बिना, दूसरा मैसेज मिलने पर पैरंट फ़्रेम, पॉप-अप नहीं खोल सकता. अगर मैसेज को किसी दूसरे क्रॉस-ऑरिजिन फ़्रेम से "चेन" जोड़ा गया है, तो भी पहला मैसेज फ़ेल हो जाता है (दूसरे शब्दों में, अगर पहला मैसेज पाने वाला व्यक्ति मैसेज को दूसरे पर भेजता है).

यह मूल रूप में और उसकी चेन, दोनों में 'उपयोगकर्ता ऐक्टिवेशन' वर्शन 2 के साथ काम करता है.