जावास्क्रिप्ट और धागे


137

क्या जावास्क्रिप्ट में मल्टी-थ्रेडिंग करने का कोई तरीका है?


2
जावास्क्रिप्ट में थ्रेड्स नहीं हैं, कम से कम अपने वर्तमान रूप में। वास्तव में आप क्या करने की कोशिश कर रहे हैं?
एरिक पोहल

3
क्या आप इसे स्वीकार किए गए उत्तर को बदल सकते हैं? stackoverflow.com/a/30891727/2576706 यह भविष्य के उपयोगकर्ता के लिए बहुत अधिक विकसित है ..
लुडोविक फेल्ट्ज

जवाबों:


109

सबसे अद्यतित समर्थन जानकारी के लिए http://caniuse.com/#search=worker देखें ।

निम्नलिखित समर्थन 2009 की स्थिति थी।


जिन शब्दों को आप Google के लिए चाहते हैं, वे जावास्क्रिप्ट वर्कर थ्रेड हैं

गियर्स के अलावा अभी कुछ भी उपलब्ध नहीं है, लेकिन इसे लागू करने के तरीके के बारे में बहुत सारी बातें हैं, इसलिए मुझे लगता है कि इस प्रश्न को देखें क्योंकि उत्तर भविष्य में कोई संदेह नहीं होगा।

यहां गियर्स के लिए प्रासंगिक प्रलेखन है: वर्करपूल एपीआई

WHATWG के पास वर्कर थ्रेड्स के लिए ड्राफ्ट की सिफारिश है: वेब वर्कर्स

और इसमें मोज़िला का DOM वर्कर थ्रेड भी है


अपडेट: जून 2009, जावास्क्रिप्ट धागे के लिए ब्राउज़र समर्थन की वर्तमान स्थिति

फ़ायरफ़ॉक्स 3.5 में वेब कर्मचारी हैं। वेब कर्मचारियों के कुछ डेमो, यदि आप उन्हें कार्रवाई में देखना चाहते हैं:

गियर्स प्लगइन को फ़ायरफ़ॉक्स में भी स्थापित किया जा सकता है।

सफ़ारी 4 , और वेबकीट नाइटलाइफ़ में श्रमिक सूत्र हैं:

Chrome में गियर्स बेक किया गया है, इसलिए यह थ्रेड्स कर सकता है, हालांकि इसके लिए उपयोगकर्ता से पुष्टिकरण प्रॉम्प्ट की आवश्यकता होती है (और यह वेब वर्कर्स के लिए एक अलग API का उपयोग करता है, हालांकि यह Gears प्लगइन के साथ किसी भी ब्राउज़र में काम करेगा):

  • Google गियर्स वर्करपूल डेमो (एक अच्छा उदाहरण नहीं है क्योंकि यह क्रोम और फ़ायरफ़ॉक्स में परीक्षण करने के लिए बहुत तेज़ चलता है, हालांकि IE इसे धीमी गति से बातचीत को देखने के लिए पर्याप्त रूप से चलाता है)

IE8 और IE9 केवल थ्रेड्स गियर्स प्लगइन के साथ कर सकते हैं


1
हालाँकि सफारी 4 वेब कर्मचारियों का समर्थन करता है लेकिन ऐसा प्रतीत होता है कि केवल फ़ायरफ़ॉक्स पोस्टमैसेज के माध्यम से जटिल वस्तुओं को पारित करने का समर्थन करता है: hacks.mozilla.org/2009/07/working-smarter-not-harder Bespin प्रोजेक्ट में वास्तविक विश्व उपयोग पर उस पोस्ट का अंतिम पैराग्राफ देखें गूगल गियर्स के संदर्भ में वर्कर एपीआई को लागू करने के लिए एक शिम के लिंक के लिए और जो सफारी 4 के कार्यकर्ता कार्यान्वयन के लिए लापता सुविधाओं को जोड़ता है और पोस्टमैसेज इंटरफ़ेस के शीर्ष पर पारदर्शी कस्टम घटनाओं को लागू करने के तरीके का विवरण देता है।
सैम हिटलर

6
अब IE9 बाहर है, आप "IE8 केवल गियर्स प्लगइन के साथ थ्रेड्स कर सकते हैं" को अपडेट कर सकते हैं "IE8 और IE9 केवल थ्रेड्स को गियर्स प्लगइन के साथ स्थापित कर सकते हैं"
बेनोइटपैरिस

2
@ inf3rno एक और धागे पर लंबी गणना करने के लिए ताकि वे ब्राउज़र UI को धीमा न करें।
सैम हसलर

6
@SamHasler आप अपने उत्तर को संशोधित करना चाह सकते हैं। वेब कर्मचारी अब सभी आधुनिक डेस्कटॉप ब्राउज़रों द्वारा समर्थित हैं। Caniuse.com/#search=worker
Rob W

2
@SamHasler यह भी ध्यान देने योग्य है कि Google Gears अब समर्थित नहीं है।
कंकाल

73

जावास्क्रिप्ट में मल्टी-थ्रेडिंग और एसिंक्रोनस करने का अलग तरीका

एचटीएमएल 5 जावास्क्रिप्ट से पहले केवल प्रति पृष्ठ एक धागे के निष्पादन की अनुमति दी गई थी।

कुछ hacky तरीके के साथ एक अतुल्यकालिक निष्पादन अनुकरण करने के लिए हुई थी यील्ड , setTimeout(), setInterval(), XMLHttpRequestया ईवेंट हैंडलर्स (इस पोस्ट के अंत के साथ एक उदाहरण के लिए देखें उपज औरsetTimeout() )।

लेकिन HTML5 के साथ अब हम फ़ंक्शन के निष्पादन को समानांतर करने के लिए वर्कर थ्रेड्स का उपयोग कर सकते हैं। यहाँ उपयोग का एक उदाहरण है।


असली मल्टी थ्रेडिंग

मल्टी-थ्रेडिंग: जावास्क्रिप्ट वर्कर थ्रेड्स

HTML5 ने वेब वर्कर थ्रेड्स देखें (देखें: ब्राउज़र कॉम्पिटिशन )
नोट: IE9 और पुराने संस्करण इसका समर्थन नहीं करते हैं।

ये वर्कर थ्रेड जावास्क्रिप्ट थ्रेड होते हैं जो पृष्ठ के प्रदर्शन को प्रभावित किए बिना पृष्ठभूमि में चलते हैं। वेब वर्कर के बारे में अधिक जानकारी के लिए प्रलेखन या इस ट्यूटोरियल को पढ़ें

यहां 3 वेब वर्कर थ्रेड्स के साथ एक सरल उदाहरण दिया गया है जो MAX_VALUE पर गिना जाता है और हमारे पृष्ठ में वर्तमान गणना मूल्य दिखाता है:

//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }

var MAX_VALUE = 10000;

/*
 *	Here are the workers
 */
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
  document.getElementById("result1").innerHTML = e.data;
}, false);


//Worker 2
var worker2 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker2.addEventListener('message', function(e) {
  document.getElementById("result2").innerHTML = e.data;
}, false);


//Worker 3
var worker3 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker3.addEventListener('message', function(e) {
    document.getElementById("result3").innerHTML = e.data;
}, false);


// Start and send data to our worker.
worker1.postMessage(MAX_VALUE); 
worker2.postMessage(MAX_VALUE); 
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

हम यह देख सकते हैं कि तीन थ्रेड्स को समरूपता में निष्पादित किया जाता है और पृष्ठ में उनके वर्तमान मूल्य को प्रिंट करता है। वे पृष्ठ को फ्रीज नहीं करते क्योंकि वे अलग थ्रेड्स के साथ पृष्ठभूमि में निष्पादित होते हैं।


बहु सूत्रण: कई iframes के साथ

इसे प्राप्त करने का एक और तरीका है कई आइफ्रेम का उपयोग करना , प्रत्येक एक थ्रेड को निष्पादित करेगा। हम दे सकते हैं आइफ्रेम यूआरएल और से कुछ मानकों आइफ्रेम आदेश परिणाम प्राप्त है और इसे वापस प्रिंट करने के लिए अपने माता पिता के साथ संवाद कर सकते हैं ( आइफ्रेम उसी डोमेन में होना चाहिए)।

यह उदाहरण सभी ब्राउज़रों में काम नहीं करता है! iframes आमतौर पर मुख्य पृष्ठ के रूप में एक ही थ्रेड / प्रक्रिया में चलते हैं (लेकिन फ़ायरफ़ॉक्स और क्रोमियम इसे अलग तरह से संभालते हैं)।

चूंकि कोड स्निपेट एकाधिक HTML फ़ाइलों का समर्थन नहीं करता है, इसलिए मैं यहां विभिन्न कोड प्रदान करूंगा:

index.html:

//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>

//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


<script>
    //This function is called by each iframe
    function threadResult(threadId, result) {
        document.getElementById("result" + threadId).innerHTML = result;
    }
</script>

thread.html:

//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
    var qs = document.location.search.split('+').join(' ');
    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params[paramName];
}

//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
    var threadId = getQueryParams('id');
    for(var i=0; i<MAX_VALUE; i++){
        parent.threadResult(threadId, i);
    }
})();

मल्टी-थ्रेडिंग का अनुकरण करें

एकल-सूत्र: setTimeout () के साथ जावास्क्रिप्ट संगामिति का अनुकरण करें

'भोले' तरीके से setTimeout()एक के बाद एक फंक्शन को अंजाम देना होगा:

setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]

लेकिन यह विधि काम नहीं करती है क्योंकि प्रत्येक कार्य को एक के बाद एक निष्पादित किया जाएगा।

हम पुनरावर्ती रूप से फ़ंक्शन को कॉल करके अतुल्यकालिक निष्पादन को अनुकरण कर सकते हैं:

var MAX_VALUE = 10000;

function thread1(value, maxValue){
    var me = this;
    document.getElementById("result1").innerHTML = value;
    value++;
  
    //Continue execution
    if(value<=maxValue)
        setTimeout(function () { me.thread1(value, maxValue); }, 0);
}

function thread2(value, maxValue){
    var me = this;
    document.getElementById("result2").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread2(value, maxValue); }, 0);
}

function thread3(value, maxValue){
    var me = this;
    document.getElementById("result3").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread3(value, maxValue); }, 0);
}

thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

जैसा कि आप देख सकते हैं यह दूसरी विधि बहुत धीमी है और ब्राउज़र को जमा देता है क्योंकि यह फ़ंक्शन को निष्पादित करने के लिए मुख्य थ्रेड का उपयोग करता है।


एकल-धागा: उपज के साथ जावास्क्रिप्ट संगामिति का अनुकरण करें

यील्ड ईसीएमएस्क्रिप्ट 6 में एक नई विशेषता है, यह केवल फ़ायरफ़ॉक्स और क्रोम के सबसे पुराने संस्करण पर काम करता है (क्रोम में आपको क्रोम में दिखाई देने वाले प्रायोगिक जावास्क्रिप्ट को सक्षम करने की आवश्यकता है : // झंडे / # सक्षम-जावास्क्रिप्ट-सद्भाव )।

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

एक जनरेटर आपको किसी फ़ंक्शन के निष्पादन को निलंबित करने और बाद में इसे फिर से शुरू करने की अनुमति देता है। एक जनरेटर को आपके कार्यों को शेड्यूल करने के लिए इस्तेमाल किया जा सकता है जिसे तकनीक कहा जाता है ट्रम्पोलिनिंग

यहाँ उदाहरण है:

var MAX_VALUE = 10000;

Scheduler = {
	_tasks: [],
	add: function(func){
		this._tasks.push(func);
	},	
	start: function(){
		var tasks = this._tasks;
		var length = tasks.length;
		while(length>0){
			for(var i=0; i<length; i++){
				var res = tasks[i].next();
				if(res.done){
					tasks.splice(i, 1);
					length--;
					i--;
				}
			}
		}
	}	
}


function* updateUI(threadID, maxValue) {
  var value = 0;
  while(value<=maxValue){
	yield document.getElementById("result" + threadID).innerHTML = value;
	value++;
  }
}

Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));

Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


3
यह वास्तव में सबसे अच्छा जवाब होना चाहिए।
जेरी लियू

14

HTML5 "साइड-स्पेक्स" के साथ अब सेटटाइमआउट (), सेटइंटरवल (), आदि के साथ जावास्क्रिप्ट को हैक करने की कोई आवश्यकता नहीं है

HTML5 और मित्र जावास्क्रिप्ट वेब वर्कर्स का परिचय देते हैं विनिर्देश । यह अतुल्यकालिक और स्वतंत्र रूप से स्क्रिप्ट चलाने के लिए एक एपीआई है।

विनिर्देश और एक ट्यूटोरियल के लिए लिंक ।


11

जावास्क्रिप्ट में कोई सच सूत्रण नहीं है। जावास्क्रिप्ट निंदनीय भाषा है कि यह है, आपको कुछ का अनुकरण करने की अनुमति देता है। यहाँ एक उदाहरण है जो मैं दूसरे दिन भर में आया था।


1
"सच्चे सूत्रण" से आपका क्या अभिप्राय है? हरे रंग के धागे सच्चे धागे हैं।
वेस

10

जावास्क्रिप्ट में कोई सच्चा मल्टी-थ्रेडिंग नहीं है, लेकिन आप एसिंक्रोनस व्यवहार का उपयोग करके प्राप्त कर सकते हैं setTimeout() और अतुल्यकालिक AJAX अनुरोध ।

वास्तव में आप क्या हासिल करने की कोशिश कर रहे हैं?


7

यहाँ अनुकरण करने का एक तरीका है जावास्क्रिप्ट में मल्टी-थ्रेडिंग

अब मैं 3 थ्रेड बनाने जा रहा हूं, जो संख्याओं की गणना करेगा, संख्याओं को 13 से विभाजित किया जा सकता है और संख्याओं को 10000000000 तक 3 के साथ विभाजित किया जा सकता है। और ये 3 फ़ंक्शन उसी समय में चलने में सक्षम नहीं हैं जैसे कि कॉन्सिफ़ेरिटी का अर्थ है। लेकिन मैं आपको एक चाल दिखाऊंगा जिससे ये फ़ंक्शन एक ही समय में पुनरावर्ती रूप से चलेंगे: jsFiddle

यह कोड मेरा है।

शरीर का अंग

    <div class="div1">
    <input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
    <input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
    <input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>

जावास्क्रिप्ट भाग

var _thread1 = {//This is my thread as object
    control: false,//this is my control that will be used for start stop
    value: 0, //stores my result
    current: 0, //stores current number
    func: function () {   //this is my func that will run
        if (this.control) {      // checking for control to run
            if (this.current < 10000000000) {
                this.value += this.current;   
                document.getElementById("1").innerHTML = this.value;
                this.current++;
            }
        }
        setTimeout(function () {  // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
            _thread1.func();    //You cannot use this.func() just try to call with your object name
        }, 0);
    },
    start: function () {
        this.control = true;   //start function
    },
    stop: function () {
        this.control = false;    //stop function
    },
    init: function () {
        setTimeout(function () {
            _thread1.func();    // the first call of our thread
        }, 0)
    }
};
var _thread2 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 13 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("2").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread2.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread2.func();
        }, 0)
    }
};
var _thread3 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 3 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("3").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread3.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread3.func();
        }, 0)
    }
};

_thread1.init();
_thread2.init();
_thread3.init();

मुझे उम्मीद है कि यह तरीका मददगार होगा।


6

आप नैरेटिव जावास्क्रिप्ट का उपयोग कर सकते हैं , एक संकलक जो आपके कोड को राज्य मशीन में बदल देगा, प्रभावी रूप से आपको थ्रेडिंग का अनुकरण करने की अनुमति देगा। यह एक "उपज" ऑपरेटर ('->' के रूप में नोट किया गया) को उस भाषा में जोड़कर करता है जो आपको एकल, रैखिक कोड ब्लॉक में अतुल्यकालिक कोड लिखने की अनुमति देता है।


4

आज आने वाला नया v8 इंजन इसका समर्थन करता है (मुझे लगता है)


3

कच्ची जावास्क्रिप्ट में, सबसे अच्छा जो आप कर सकते हैं वह कुछ अतुल्यकालिक कॉल (xmlhttprequest) का उपयोग कर रहा है, लेकिन यह वास्तव में थ्रेडिंग और बहुत सीमित नहीं है। Google गियर्स ब्राउज़र में कई एपीआई जोड़ता है, जिनमें से कुछ को थ्रेडिंग समर्थन के लिए उपयोग किया जा सकता है।


1
Google Gears API अब उपलब्ध नहीं है।
लुडोविक फेल्ट्ज

3

यदि आप किसी AJAX सामान का उपयोग नहीं कर सकते हैं या नहीं करना चाहते हैं, तो एक iframe या दस का उपयोग करें! ;) आप क्रॉस ब्राउज़र तुलनीय मुद्दों या डॉट नेट AJAX आदि के साथ वाक्यविन्यास मुद्दों के बारे में चिंता किए बिना मास्टर पेज के समानांतर में iframes में चलने की प्रक्रिया हो सकती है, और आप मास्टर पेज के जावास्क्रिप्ट (जावास्क्रिप्ट जो इसे आयात किया गया है सहित) से कॉल कर सकते हैं iframe।

उदाहरण के लिए, एक माता-पिता iframe egFunction()में, माता-पिता दस्तावेज़ में कॉल करने के लिए एक बार iframe सामग्री लोड हो गई है (यह अतुल्यकालिक भाग है)

parent.egFunction();

गतिशील रूप से iframes भी उत्पन्न करते हैं इसलिए यदि आप चाहें तो मुख्य HTML कोड उनसे मुक्त है।


1
यह विवरण मेरी पसंद के हिसाब से बहुत कम था। क्या आप इस तकनीक को करने के बारे में विस्तार से बता सकते हैं, या कुछ कोड दिखाने वाले ट्यूटोरियल के लिए कुछ लिंक पोस्ट कर सकते हैं?
ऑलिगॉफ्रेन

3

एक अन्य संभावित विधि जावास्क्रिप्ट पर्यावरण में एक जावास्क्रिप्ट इंटरप्रेटर का उपयोग कर रहा है।

कई दुभाषियों को बनाकर और मुख्य धागे से उनके निष्पादन को नियंत्रित करके, आप अपने स्वयं के वातावरण में चल रहे प्रत्येक धागे के साथ बहु-थ्रेडिंग का अनुकरण कर सकते हैं।

दृष्टिकोण कुछ हद तक वेब श्रमिकों के समान है, लेकिन आप ब्राउज़र वैश्विक वातावरण में दुभाषिया पहुंच प्रदान करते हैं।

मैंने इसे प्रदर्शित करने के लिए एक छोटा प्रोजेक्ट बनाया ।

इस ब्लॉग पोस्ट में अधिक विस्तृत विवरण ।


1

जावास्क्रिप्ट में धागे नहीं हैं, लेकिन हमारे पास कार्यकर्ता हैं।

यदि आपको साझा वस्तुओं की आवश्यकता नहीं है, तो श्रमिक एक अच्छा विकल्प हो सकते हैं।

अधिकांश ब्राउज़र कार्यान्वयन वास्तव में सभी कोर में श्रमिकों का प्रसार करेंगे, जिससे आप सभी कोर का उपयोग कर सकेंगे। आप इसका एक डेमो यहां देख सकते हैं ।

मैंने task.js नाम से एक लाइब्रेरी विकसित की है जो ऐसा करने में बहुत आसान है।

कार्य .js सभी कोर पर चलाने के लिए सीपीयू गहन कोड प्राप्त करने के लिए सरलीकृत इंटरफ़ेस (नोड। जेएस, और वेब)

एक उदाहरण होगा

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

0

एचटीएमएल 5 विनिर्देश के साथ आपको उसी के लिए बहुत अधिक जेएस लिखने या कुछ हैक खोजने की आवश्यकता नहीं है।

HTML5 में पेश की गई एक विशेषता वेब वर्कर्स है जो पृष्ठ के प्रदर्शन को प्रभावित किए बिना पृष्ठभूमि में स्वतंत्र रूप से अन्य लिपियों में चल रहा जावास्क्रिप्ट है।

यह लगभग सभी ब्राउज़रों में समर्थित है:

क्रोम - 4.0+

IE - 10.0+

मोज़िला - 3.5+

सफारी - 4.0+

ओपेरा - 11.5+

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.