एक एसिंक्रोनस जावास्क्रिप्ट फ़ंक्शन को कॉल करें


222

सबसे पहले, यह एक बहुत ही विशिष्ट मामला है, यह एक बहुत ही तुल्यकालिक कोडबेस में एक अतुल्यकालिक कॉल को वापस करने का गलत तरीका है, जो हजारों लाइनों की लंबी और समय है, वर्तमान में बदलाव करने की क्षमता नहीं रखता है। यह सही।" यह मेरे होने के हर तंतु को चोट पहुँचाता है, लेकिन वास्तविकता और आदर्श अक्सर नहीं होते हैं। मुझे पता है कि यह बेकार है।

ठीक है, इस तरह से, मैं इसे कैसे बनाऊं ताकि मैं कर सकूं:

function doSomething() {

  var data;

  function callBack(d) {
    data = d;
  }

  myAsynchronousCall(param1, callBack);

  // block here and return data when the callback is finished
  return data;
}

उदाहरण (या इसके अभाव) सभी पुस्तकालयों और / या संकलक का उपयोग करते हैं, दोनों इस समाधान के लिए व्यवहार्य नहीं हैं। मुझे यह कैसे बनाने के लिए एक ठोस उदाहरण की आवश्यकता है (जैसे कॉलबैक न होने तक doSomething फ़ंक्शन को न छोड़ें) UI को फ्रीज़ किए बिना। यदि जेएस में ऐसा संभव है।


16
केवल ब्राउज़र ब्लॉक करना और प्रतीक्षा करना संभव नहीं है। वे ऐसा नहीं करेंगे।
इंगित

2
जावास्क्रिप्ट डोज़ेंट में अधिकांश ब्राउज़रों पर अवरोधक तंत्र होता है ... आप एक कॉलबैक बनाना चाहते हैं जिसे कॉल किया जाता है जब डेटा वापस करने के लिए async कॉल समाप्त हो जाती है
नादिर मुज़फ्फर

8
आप ब्राउज़र को यह बताने का एक तरीका पूछ रहे हैं कि "मुझे पता है कि मैंने आपको पिछले फ़ंक्शन को अतुल्यकालिक रूप से चलाने के लिए कहा था, लेकिन मैं वास्तव में इसका मतलब होगा!"। आप यह भी उम्मीद करेंगे कि क्यों संभव है?
वेन

2
धन्यवाद डैन एडिट के लिए। मैं सख्ती से कठोर नहीं था, लेकिन आपका शब्दांकन बेहतर है।
रॉबर्ट सी। बर्थ

2
@ RobertC.Barth यह अब जावास्क्रिप्ट के साथ भी संभव है। async प्रतीक्षा कार्य मानक में अभी तक पुष्टि नहीं की गई है, लेकिन ES2017 में होने की योजना है। अधिक विस्तार के लिए नीचे मेरा जवाब देखें।
जॉन

जवाबों:


135

"मुझे इसके बारे में नहीं बताना चाहिए कि मुझे इसे कैसे करना चाहिए" सही तरीका "या जो भी हो"

ठीक है। लेकिन आपको वास्तव में इसे सही तरीके से करना चाहिए ... या जो भी हो

"मुझे इसे ब्लॉक करने के तरीके का एक ठोस उदाहरण चाहिए ... यूआई को फ्रीज किए बिना। यदि जेएस में ऐसा संभव है।"

नहीं, UI को ब्लॉक किए बिना रनिंग जावास्क्रिप्ट को ब्लॉक करना असंभव है।

जानकारी की कमी को देखते हुए, समाधान की पेशकश करना कठिन है, लेकिन एक विकल्प यह हो सकता है कि ग्लोबल वैरिएबल की जांच के लिए कॉलिंग फ़ंक्शन कुछ मतदान करें, फिर कॉलबैक dataको वैश्विक पर सेट करें।

function doSomething() {

      // callback sets the received data to a global var
  function callBack(d) {
      window.data = d;
  }
      // start the async
  myAsynchronousCall(param1, callBack);

}

  // start the function
doSomething();

  // make sure the global is clear
window.data = null

  // start polling at an interval until the data is found at the global
var intvl = setInterval(function() {
    if (window.data) { 
        clearInterval(intvl);
        console.log(data);
    }
}, 100);

यह सब मानता है कि आप संशोधित कर सकते हैं doSomething()। मुझे नहीं पता कि कार्ड में है या नहीं।

यदि इसे संशोधित किया जा सकता है, तो मुझे नहीं पता कि आप doSomething()अन्य कॉलबैक से कॉल किए जाने के लिए कॉलबैक को पास क्यों नहीं करेंगे , लेकिन इससे पहले कि मैं मुसीबत में पड़ूं, बेहतर होता हूं। ;)


ओह, क्या बिल्ली है। आपने एक उदाहरण दिया जो बताता है कि इसे सही तरीके से किया जा सकता है, इसलिए मैं उस समाधान को दिखाने जा रहा हूं ...

function doSomething( func ) {

  function callBack(d) {
    func( d );
  }

  myAsynchronousCall(param1, callBack);

}

doSomething(function(data) {
    console.log(data);
});

चूँकि आपके उदाहरण में एक कॉलबैक शामिल है जो कि async कॉल करने के लिए दिया गया है, सही तरीका यह होगा doSomething()कि कॉलबैक से एक फ़ंक्शन को पास किया जाए।

यदि कॉलबैक केवल एक ही चीज़ कर रहा है, तो आप funcसीधे ही पास होंगे ...

myAsynchronousCall(param1, func);

22
हाँ, मुझे पता है कि इसे सही तरीके से कैसे किया जाता है, मुझे यह जानना होगा कि कैसे / यदि इसे गलत तरीके से बताए गए कारण के लिए किया जा सकता है। जब तक myAsynchronousCall कॉलबैक फ़ंक्शन को कॉल पूरा नहीं करता है तब तक यह क्रूक्स मैं doSomething () को छोड़ना नहीं चाहता। Bleh, यह नहीं किया जा सकता है, जैसा कि मुझे संदेह था, मुझे बस मुझे वापस करने के लिए इंटनेट के एकत्रित ज्ञान की आवश्यकता थी। धन्यवाद। :-)
रॉबर्ट सी। बर्थ

2
@ RobertC.Barth: हाँ, आपका संदेह दुर्भाग्य से सही था।

क्या यह मुझे या केवल "सही ढंग से किया गया" संस्करण का काम है? प्रश्न में एक रिटर्न कॉल शामिल था, जिसके पहले कुछ ऐसा होना चाहिए जो कि एस्क्वायस कॉल समाप्त होने की प्रतीक्षा करता है, जो इस उत्तर का पहला भाग कवर नहीं करता है ...
ravemir

@ravemir: उत्तर में कहा गया है कि वह जो करना चाहता है वह करना संभव नहीं है । यह समझने के लिए महत्वपूर्ण हिस्सा है। दूसरे शब्दों में, आप अतुल्यकालिक कॉल नहीं कर सकते हैं और UI को अवरुद्ध किए बिना एक मान लौटा सकते हैं। तो पहला समाधान एक वैश्विक चर का उपयोग करके एक बदसूरत हैक है और यह देखने के लिए कि क्या चर को संशोधित किया गया है। दूसरा संस्करण सही तरीका है।

1
@ लियोनार्डो: यह रहस्यमय कार्य है जिसे प्रश्न में कहा जाता है। मूल रूप से यह किसी भी चीज़ का प्रतिनिधित्व करता है जो कोड को अतुल्यकालिक रूप से चलाता है और एक परिणाम उत्पन्न करता है जिसे प्राप्त करने की आवश्यकता होती है। तो यह एक AJAX अनुरोध की तरह हो सकता है। आप callbackफ़ंक्शन को फ़ंक्शन को पास करते हैं myAsynchronousCall, जो इसके एसिंक्स सामान करता है और कॉलबैक को पूरा होने पर आमंत्रित करता है। यहाँ एक डेमो है।

60

Async फ़ंक्शन , ES2017 में एक सुविधा , वादे (async कोड का एक विशेष रूप) और awaitकीवर्ड का उपयोग करके async कोड को सिंक करते हैं । इसके अलावा कीवर्ड नीचे कोड उदाहरण में नोटिस asyncके सामनेfunction कि एसिंक्स / वेट फ़ंक्शन को दर्शाता है। awaitकीवर्ड एक समारोह के साथ पहले से तय में किया जा रहा बिना काम नहीं करेगा asyncकीवर्ड। चूंकि वर्तमान में इसका कोई अपवाद नहीं है, जिसका अर्थ है कि कोई शीर्ष स्तर प्रतीक्षा नहीं करेगा (शीर्ष स्तर किसी भी फ़ंक्शन के बाहर प्रतीक्षा का अर्थ है)। हालांकि शीर्ष स्तर के लिएawait एक प्रस्ताव है

ES2017 को 27 जून, 2017 को जावास्क्रिप्ट के लिए मानक के रूप में (यानी अंतिम रूप दिया गया) प्रमाणित किया गया था। Async प्रतीक्षा आपके ब्राउज़र में पहले से ही काम कर सकती है, लेकिन यदि आप अभी भी जावास्क्रिप्ट ट्रांसपिलर का उपयोग करके कार्यक्षमता का उपयोग नहीं कर सकते हैं जैसे कोलाहल या Traceur । Chrome 55 में async फ़ंक्शंस का पूरा समर्थन है। इसलिए यदि आपके पास एक नया ब्राउज़र है, तो आप नीचे दिए गए कोड को आज़मा सकते हैं।

देख ब्राउज़र संगतता के लिए kangax की es2017 संगतता तालिका

यहाँ एक उदाहरण async वेट फंक्शन है जिसे doAsyncतीन एक दूसरा पॉज़ कहते हैं और शुरू से प्रत्येक पॉज़ के बाद समय के अंतर को प्रिंट करता है:

function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}

function doSomethingAsync () {
  return timeoutPromise(1000);
}

async function doAsync () {
  var start = Date.now(), time;
  console.log(0);
  time = await doSomethingAsync();
  console.log(time - start);
  time = await doSomethingAsync();
  console.log(time - start);
  time = await doSomethingAsync();
  console.log(time - start);
}

doAsync();

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

इसलिए, जब से बस रुकने का इंतजार होता है, तब बाकी मूल्य को निष्पादित करने से पहले आप एक मान को खोल देते हैं, जिसका उपयोग आप लूप के लिए और अंदर के फंक्शन कॉल के लिए कर सकते हैं, जैसे नीचे दिए गए उदाहरण में, जो एक सरणी में प्रतीक्षित समय के अंतर को इकट्ठा करता है और सरणी को प्रिंट करता है।

function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}

function doSomethingAsync () {
  return timeoutPromise(1000);
}

// this calls each promise returning function one after the other
async function doAsync () {
  var response = [];
  var start = Date.now();
  // each index is a promise returning function
  var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
  for(var i = 0; i < promiseFuncs.length; ++i) {
    var promiseFunc = promiseFuncs[i];
    response.push(await promiseFunc() - start);
    console.log(response);
  }
  // do something with response which is an array of values that were from resolved promises.
  return response
}

doAsync().then(function (response) {
  console.log(response)
})

Async फ़ंक्शन अपने आप ही एक वादा लौटाता है, ताकि आप उस प्रतिज्ञा के रूप में उपयोग कर सकें जैसे मैं ऊपर या किसी अन्य async प्रतीक्षा फ़ंक्शन के भीतर करता हूँ।

उपरोक्त फ़ंक्शन प्रत्येक अनुरोध के लिए एक और अनुरोध भेजने से पहले प्रतीक्षा करेगा यदि आप अनुरोधों को समवर्ती रूप से भेजना चाहते हैं तो आप Promise.all का उपयोग कर सकते हैं ।

// no change
function timeoutPromise (time) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(Date.now());
    }, time)
  })
}

// no change
function doSomethingAsync () {
  return timeoutPromise(1000);
}

// this function calls the async promise returning functions all at around the same time
async function doAsync () {
  var start = Date.now();
  // we are now using promise all to await all promises to settle
  var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
  return responses.map(x=>x-start);
}

// no change
doAsync().then(function (response) {
  console.log(response)
})

यदि वादा संभवतः अस्वीकार करता है, तो आप इसे एक कोशिश में पकड़ सकते हैं या कोशिश करने वाले को छोड़ सकते हैं और त्रुटि को async / प्रतीक्षा कार्यों को पकड़ने के लिए प्रचारित करने दें। विशेष रूप से Node.js. में अनचाहे किए गए वादों को छोड़ने के लिए आपको सावधान रहना चाहिए नीचे कुछ उदाहरण दिए गए हैं जिनसे पता चलता है कि त्रुटियाँ कैसे काम करती हैं।

function timeoutReject (time) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
    }, time)
  })
}

function doErrorAsync () {
  return timeoutReject(1000);
}

var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);

async function unpropogatedError () {
  // promise is not awaited or returned so it does not propogate the error
  doErrorAsync();
  return "finished unpropogatedError successfully";
}

unpropogatedError().then(log).catch(logErr)

async function handledError () {
  var start = Date.now();
  try {
    console.log((await doErrorAsync()) - start);
    console.log("past error");
  } catch (e) {
    console.log("in catch we handled the error");
  }
  
  return "finished handledError successfully";
}

handledError().then(log).catch(logErr)

// example of how error propogates to chained catch method
async function propogatedError () {
  var start = Date.now();
  var time = await doErrorAsync() - start;
  console.log(time - start);
  return "finished propogatedError successfully";
}

// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)

अगर आप यहां जाएं तो आप आगामी ECMAScript संस्करणों के लिए तैयार प्रस्तावों को देख सकते हैं।

इसका एक विकल्प जो सिर्फ ES2015 (ES6) के साथ इस्तेमाल किया जा सकता है वह एक विशेष फ़ंक्शन का उपयोग करना है जो एक जनरेटर फ़ंक्शन को लपेटता है। जेनरेटर फ़ंक्शंस में एक उपज कीवर्ड होता है जिसका उपयोग आस-पास के फ़ंक्शन के साथ प्रतीक्षा कीवर्ड को दोहराने के लिए किया जा सकता है। उपज कीवर्ड और जनरेटर फ़ंक्शन एक बहुत अधिक सामान्य उद्देश्य हैं और कई और चीजें कर सकते हैं फिर बस async प्रतीक्षा कार्य करता है। यदि आप एक जनरेटर फंक्शन रैपर चाहते हैं, जिसका उपयोग async प्रतीक्षा करने के लिए किया जा सकता है तो मैं co.js की जाँच करूँगा । वैसे, सह का कार्य जैसे कि async प्रतीक्षा कार्य एक वादा वापस करते हैं। ईमानदारी से, हालांकि इस बिंदु पर ब्राउज़र की संगतता जनरेटर कार्यों और async दोनों कार्यों के लिए समान है, इसलिए यदि आप सिर्फ async प्रतीक्षा कार्यशीलता चाहते हैं तो आपको co.js.s के बिना Async फ़ंक्शन का उपयोग करना चाहिए।

IE को छोड़कर सभी प्रमुख वर्तमान ब्राउज़रों (क्रोम, सफारी और एज) में Async फ़ंक्शंस (2017 के अनुसार) के लिए ब्राउज़र समर्थन वास्तव में अब बहुत अच्छा है।


2
मुझे यह उत्तर पसंद है
ycomp

1
कितनी दूर हम आए हैं :)
डेरेक

3
यह एक शानदार जवाब है, लेकिन मूल पोस्टर समस्या के लिए, मुझे लगता है कि यह सब एक स्तर पर समस्या को बढ़ाता है। कहते हैं कि वह एक async फ़ंक्शन में doSomething को एक प्रतीक्षा के साथ बदल देता है। वह फ़ंक्शन अब एक वादा लौटाता है और अतुल्यकालिक है, इसलिए उस फ़ंक्शन को जो भी कॉल करता है, उसे फिर से उसी समस्या से निपटना होगा।
dpwrussell

1
@dpussussell यह सच है, कोड बेस में एसिंक्स फ़ंक्शन और वादों की एक रेंगना है। सब कुछ में रेंगने से वादों को हल करने का सबसे अच्छा तरीका केवल तुल्यकालिक कॉलबैक लिखना है एक सिंक्रोनाइज़ वैल्यू को वापस करने का कोई तरीका नहीं है जब तक कि आप इस twitter.com/sebmarkbage/status-941214259505119232 जैसे कुछ बेहद अजीब और विवादास्पद न करें। सलाह देते हैं। मैं प्रश्न का अंत करने के लिए एक सम्पादन जोड़ दूंगा क्योंकि यह पूछे गए प्रश्न का पूरी तरह से उत्तर देगा और केवल शीर्षक का उत्तर नहीं देगा।
जॉन

यह एक महान जवाब है +1 और सभी, लेकिन जैसा लिखा है, मुझे नहीं लगता कि यह कॉलबैक का उपयोग करने की तुलना में किसी भी कम जटिल है।
अल्टिमस प्राइम

47

JQuery के वादों पर एक नज़र डालें:

http://api.jquery.com/promise/

http://api.jquery.com/jQuery.when/

http://api.jquery.com/deferred.promise/

कोड को रिफलेक्टर करें:

    var dfd = new jQuery.Deferred ();


    फ़ंक्शन कॉलबैक (डेटा) {
       dfd.notify (डेटा);
    }

    // async कॉल करें।
    myAsynchronousCall (param1, callBack);

    फ़ंक्शन doSomething (डेटा) {
     // डेटा के साथ सामान ...
    }

    $ .जब (DFD) तो फिर (DoSomething);



3
इस उत्तर के लिए +1, यह सही है। हालांकि, मैं के साथ लाइन को अपडेट करेंगे dfd.notify(data)करने के लिएdfd.resolve(data)
जेसन

7
क्या यह समकालिक होने का भ्रम देने वाले कोड का मामला है, वास्तव में अतुल्यकालिक नहीं है?
सूरशाज़

2
वादे IMO केवल अच्छी तरह से संगठित कॉलबैक हैं :) अगर आपको एक अतुल्यकालिक कॉल की आवश्यकता है तो कहने दें कि कुछ वस्तु आरंभीकरण, वादों से थोड़ा फर्क पड़ता है।
webduvet

10
वादे सिंक नहीं होते।
वैन एस

6

Http://taskjs.org/ पर एक अच्छा समाधान है

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

यहाँ परियोजना GitHub से उदाहरण कोड है

var { Deferred } = task;

spawn(function() {
    out.innerHTML = "reading...\n";
    try {
        var d = yield read("read.html");
        alert(d.responseText.length);
    } catch (e) {
        e.stack.split(/\n/).forEach(function(line) { console.log(line) });
        console.log("");
        out.innerHTML = "error: " + e;
    }

});

function read(url, method) {
    method = method || "GET";
    var xhr = new XMLHttpRequest();
    var deferred = new Deferred();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status >= 400) {
                var e = new Error(xhr.statusText);
                e.status = xhr.status;
                deferred.reject(e);
            } else {
                deferred.resolve({
                    responseText: xhr.responseText
                });
            }
        }
    };
    xhr.open(method, url, true);
    xhr.send();
    return deferred.promise;
}

3

आप सिंक- आरपीसी के साथ तुल्यकालिक होने के लिए एनओडीजेएस में अतुल्यकालिक जावास्क्रिप्ट को बाध्य कर सकते हैं

यह निश्चित रूप से आपके UI को फ्रीज कर देगा, इसलिए मैं अभी भी एक naysayer हूं जब यह आता है कि क्या शॉर्टकट को लेना संभव है जिसे आपको लेने की आवश्यकता है। जावास्क्रिप्ट में वन एंड ओनली थ्रेड को निलंबित करना संभव नहीं है, भले ही NodeJS आपको कभी-कभी इसे ब्लॉक करने देता हो। कोई कॉलबैक, ईवेंट, कुछ भी अतुल्यकालिक सब कुछ संसाधित नहीं कर पाएगा जब तक कि आपका वादा हल नहीं हो जाता। इसलिए जब तक कि पाठक के पास ओपी (या, मेरे मामले में) एक अपरिहार्य स्थिति नहीं है, बिना कॉलबैक, घटनाओं आदि के साथ एक शानदार शेल स्क्रिप्ट लिख रहे हैं), यह मत करो!

लेकिन यहाँ आप यह कैसे कर सकते हैं:

./calling-file.js

var createClient = require('sync-rpc');
var mySynchronousCall = createClient(require.resolve('./my-asynchronous-call'), 'init data');

var param1 = 'test data'
var data = mySynchronousCall(param1);
console.log(data); // prints: received "test data" after "init data"

./my-asynchronous-call.js

function init(initData) {
  return function(param1) {
    // Return a promise here and the resulting rpc client will be synchronous
    return Promise.resolve('received "' + param1 + '" after "' + initData + '"');
  };
}
module.exports = init;

सीमाएं:

ये दोनों कैसे sync-rpcलागू किया जाता है, इसका परिणाम है, जो कि गाली देने से है require('child_process').spawnSync:

  1. यह ब्राउज़र में काम नहीं करेगा।
  2. आपके फ़ंक्शन के तर्क क्रमबद्ध होने चाहिए । आपकी दलीलें अंदर और बाहर से JSON.stringifyगुजरेंगी, इसलिए प्रोटोटाइप चेन जैसे फंक्शंस और नॉन-एनेमरेबल प्रॉपर्टीज खो जाएंगी।

1

आप इसे कॉलबैक में भी बदल सकते हैं।

function thirdPartyFoo(callback) {    
  callback("Hello World");    
}

function foo() {    
  var fooVariable;

  thirdPartyFoo(function(data) {
    fooVariable = data;
  });

  return fooVariable;
}

var temp = foo();  
console.log(temp);

0

आप जो चाहते हैं वह वास्तव में अब संभव है। यदि आप किसी सर्विस वर्कर में एसिंक्रोनस कोड, और किसी वेब वर्कर में सिंक्रोनस कोड को चला सकते हैं, तो आप वेब वर्कर को सर्विस वर्कर को सिंक्रोनस XHR भेज सकते हैं, और जबकि सर्विस वर्कर async चीजें करता है, वेब वर्कर धागा इंतजार करेगा। यह एक महान दृष्टिकोण नहीं है, लेकिन यह काम कर सकता है।


-4

यदि आप आवश्यकता को कम करते हैं, तो आप जिस विचार को प्राप्त करने की आशा करते हैं, वह संभव हो सकता है

यदि आपका रनटाइम ES6 विनिर्देशन का समर्थन करता है तो नीचे दिया गया कोड संभव है।

Async फ़ंक्शन के बारे में अधिक

async function myAsynchronousCall(param1) {
    // logic for myAsynchronous call
    return d;
}

function doSomething() {

  var data = await myAsynchronousCall(param1); //'blocks' here until the async call is finished
  return data;
}

4
फ़ायरफ़ॉक्स त्रुटि देता है SyntaxError: await is only valid in async functions and async generators:। यह उल्लेख करने के लिए नहीं कि पैरा 1 को परिभाषित नहीं किया गया है (और इसका उपयोग भी नहीं किया गया है)।
हार्वे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.