javascript - मैं एक एसिंक्रोनस कॉल से प्रतिक्रिया कैसे वापस कर सकता हूं?




ajax asynchronous (20)

मेरे पास एक फ़ंक्शन foo जो अजाक्स अनुरोध करता है। मैं foo से प्रतिक्रिया कैसे वापस कर सकता हूं?

मैंने success कॉलबैक से मूल्य वापस करने की कोशिश की और साथ ही फ़ंक्शन के अंदर स्थानीय चर के प्रति प्रतिक्रिया को आवंटित करने और उसे वापस करने का प्रयास किया, लेकिन इनमें से कोई भी तरीका वास्तव में प्रतिक्रिया वापस नहीं करता है।

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;
}

var result = foo(); // It always ends up being `undefined`.

https://code.i-harness.com


→ विभिन्न उदाहरणों के साथ एसिंक व्यवहार के बारे में अधिक सामान्य स्पष्टीकरण के लिए, कृपया एक फ़ंक्शन के अंदर इसे संशोधित करने के बाद मेरा चर अपरिवर्तित क्यों है? असीमित कोड संदर्भ

→ यदि आप पहले से ही समस्या को समझते हैं, तो नीचे दिए गए संभावित समाधानों पर जाएं।

समस्या

Ajax में asynchronous के लिए खड़ा है। इसका मतलब है कि अनुरोध भेजना (या प्रतिक्रिया प्राप्त करना) सामान्य निष्पादन प्रवाह से बाहर निकाला जाता है। आपके उदाहरण में, $.ajax तुरंत और अगला कथन लौटाता है, return result; , success कॉलबैक के रूप में पारित समारोह से पहले निष्पादित किया जाता है।

यहां एक समानता है जो उम्मीद है कि तुल्यकालिक और असिंक्रोनस प्रवाह स्पष्ट के बीच का अंतर बनाता है:

एक समय का

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

वही हो रहा है जब आप "सामान्य" कोड वाले फ़ंक्शन कॉल करते हैं:

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

भले ही findItem निष्पादित करने में लंबा समय लगे, फिर भी कोई var item = findItem(); बाद आ रहा है var item = findItem(); फ़ंक्शन परिणाम लौटने तक प्रतीक्षा करना होगा

अतुल्यकालिक

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

जब आप अजाक्स अनुरोध करते हैं तो वही हो रहा है।

findItem(function(item) {
    // Do something with item
});
doSomethingElse();

प्रतिक्रिया की प्रतीक्षा करने के बजाय, निष्पादन तुरंत जारी रहता है और अजाक्स कॉल के बाद बयान निष्पादित किया जाता है। अंततः प्रतिक्रिया प्राप्त करने के लिए, प्रतिक्रिया मिलने के बाद आप एक समारोह कहलाते हैं, कॉलबैक (कुछ नोटिस? वापस कॉल करें ?)। कॉलबैक कहने से पहले उस कॉल के बाद आने वाला कोई भी बयान निष्पादित किया जाता है।

समाधान की)

जावास्क्रिप्ट की असीमित प्रकृति को गले लगाओ! जबकि कुछ एसिंक्रोनस ऑपरेशंस सिंक्रोनस समकक्ष प्रदान करते हैं (इसलिए "अजाक्स" भी), आमतौर पर उन्हें उपयोग करने के लिए निराश किया जाता है, खासकर ब्राउज़र संदर्भ में।

आप पूछना बुरा क्यों है?

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

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

निम्नलिखित में हम तीन अलग-अलग समाधान देखेंगे जो सभी एक दूसरे के शीर्ष पर हैं:

  • async/await await के साथ वादे (ES2017 +, पुराने ब्राउज़र में उपलब्ध है यदि आप एक ट्रांसलेटर या पुनर्विक्रेता का उपयोग करते हैं)
  • कॉलबैक (नोड में लोकप्रिय)
  • then() साथ वादे then() (ES2015 +, पुराने ब्राउज़र में उपलब्ध है यदि आप कई वादे पुस्तकालयों में से एक का उपयोग करते हैं)

सभी तीन वर्तमान ब्राउज़र में उपलब्ध हैं, और नोड 7+।

ES2017 +: async/await साथ वादा async/await

2017 में जारी ईसीएमएस्क्रिप्ट संस्करण ने एसिंक्रोनस फ़ंक्शंस के लिए सिंटैक्स-स्तरीय समर्थन प्रस्तुत किया। async और await की मदद से, आप "तुल्यकालिक शैली" में एसिंक्रोनस लिख सकते हैं। कोड अभी भी असंकालिक है, लेकिन इसे पढ़ने / समझना आसान है।

async/await वादे के शीर्ष पर बनाता है: एक async समारोह हमेशा एक वादा देता है। एक वादा "अनचाहे" का await और या तो वादा को अस्वीकार कर दिया गया था या तो वादा को अस्वीकार कर दिया गया था या तो वादा को खारिज कर दिया गया था।

महत्वपूर्ण: आप केवल async फ़ंक्शन के अंदर await उपयोग कर सकते हैं। इसका मतलब है कि बहुत ऊपर के स्तर पर, आपको अभी भी वादे के साथ सीधे काम करना है।

आप async/await बारे में अधिक पढ़ सकते हैं और एमडीएन पर await कर सकते हैं।

यहां एक उदाहरण दिया गया है जो उपरोक्त देरी के शीर्ष पर बनाता है:

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}


async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for 3 seconds (just for the sake of this example)
    await delay();
    // GET information about each book
    return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
  } catch(error) {
    // If any of the awaited promises was rejected, this catch block
    // would catch the rejection reason
    return null;
  }
}

// Async functions always return a promise
getAllBooks()
  .then(function(books) {
    console.log(books);
  });

वर्तमान browser और node संस्करण async/await समर्थन करते हैं। आप regenerator (या उपकरण जो पुनर्विक्रेता का उपयोग करते हैं, जैसे Babel ) की मदद से ईएस 5 में अपना कोड बदलकर पुराने वातावरण का समर्थन कर सकते हैं।

कार्यों को कॉलबैक स्वीकार करने दें

एक कॉलबैक बस एक समारोह को दूसरे समारोह में पारित किया जाता है। वह अन्य फ़ंक्शन जब भी तैयार हो जाता है तो फ़ंक्शन को कॉल कर सकता है। एसिंक्रोनस प्रक्रिया के संदर्भ में, जब भी एसिंक्रोनस प्रक्रिया पूरी की जाती है तो कॉलबैक को कॉल किया जाएगा। आमतौर पर, परिणाम कॉलबैक को पास किया जाता है।

प्रश्न के उदाहरण में, आप foo को कॉलबैक स्वीकार कर सकते हैं और success कॉलबैक के रूप में इसका उपयोग कर सकते हैं। तो यह

var result = foo();
// Code that depends on 'result'

हो जाता है

foo(function(result) {
    // Code that depends on 'result'
});

यहां हमने फ़ंक्शन "इनलाइन" परिभाषित किया है लेकिन आप किसी फ़ंक्शन संदर्भ को पास कर सकते हैं:

function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

foo खुद को निम्नानुसार परिभाषित किया गया है:

function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

callback उस फ़ंक्शन को संदर्भित करेगा जब हम इसे कॉल करते हैं, हम इसे कॉल करते हैं और हम इसे success पास करते हैं। एक बार अजाक्स अनुरोध सफल होने के बाद, $.ajax callback को कॉल करेगा और callback को प्रतिक्रिया देगी (जिसे result साथ संदर्भित किया जा सकता है, क्योंकि इस तरह हमने कॉलबैक को परिभाषित किया है)।

आप कॉलबैक में पास करने से पहले प्रतिक्रिया को भी संसाधित कर सकते हैं:

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}

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

ES2015 +: then() साथ वादे then()

then() एसीएमएस्क्रिप्ट 6 (ES2015) की एक नई सुविधा है, लेकिन इसमें पहले से ही अच्छा ब्राउज़र समर्थन है । ऐसे कई पुस्तकालय भी हैं जो मानक वादा एपीआई को लागू करते हैं और अतुल्यकालिक कार्यों (उदाहरण के लिए bluebird ) के उपयोग और संरचना को कम करने के लिए अतिरिक्त विधियां प्रदान करते हैं।

वादे भविष्य के मूल्यों के लिए कंटेनर हैं। जब वादा मूल्य प्राप्त करता है (इसे हल किया जाता है ) या जब इसे रद्द कर दिया जाता है ( अस्वीकार कर दिया जाता है ), यह अपने सभी "श्रोताओं" को सूचित करता है जो इस मूल्य तक पहुंचना चाहते हैं।

सादा कॉलबैक पर लाभ यह है कि वे आपको अपने कोड को कम करने की अनुमति देते हैं और उन्हें लिखना आसान होता है।

वादा का उपयोग करने का एक सरल उदाहरण यहां दिया गया है:

function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected 
    // (it would not happen in this example, since `reject` is not called).
  });

हमारे अजाक्स कॉल पर लागू हम इस तरह के वादे का उपयोग कर सकते हैं:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("/echo/json")
  .then(function(result) {
    // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });

प्रस्ताव का वादा करने वाले सभी फायदों का वर्णन इस उत्तर के दायरे से बाहर है, लेकिन यदि आप नया कोड लिखते हैं, तो आपको गंभीरता से उन पर विचार करना चाहिए। वे आपके कोड का एक महान अमूर्तता और अलगाव प्रदान करते हैं।

वादे के बारे में अधिक जानकारी: एचटीएमएल 5 चट्टानों - जावास्क्रिप्ट वादा करता है

साइड नोट: jQuery की स्थगित वस्तुओं

डिफर्ड ऑब्जेक्ट्स jQuery के वादे के कस्टम कार्यान्वयन हैं (वादा API को मानकीकृत करने से पहले)। वे लगभग वादे की तरह व्यवहार करते हैं लेकिन थोड़ा अलग एपीआई का पर्दाफाश करते हैं।

JQuery की प्रत्येक अजाक्स विधि पहले से ही "स्थगित वस्तु" (वास्तव में एक स्थगित वस्तु का वादा) लौटाती है जिसे आप अपने कार्य से वापस कर सकते हैं:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

साइड नोट: वादा गेटचास

ध्यान रखें कि वादे और स्थगित वस्तुएं भविष्य के मूल्य के लिए केवल कंटेनर हैं, वे मूल्य स्वयं नहीं हैं। उदाहरण के लिए, मान लें कि आपके पास निम्न था:

function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

यह कोड उपरोक्त एसिंक्रोनि मुद्दों को गलत समझाता है। विशेष रूप से, $.ajax() कोड को फ्रीज नहीं करता है, जबकि यह आपके सर्वर पर 'पासवर्ड' पृष्ठ की जांच करता है - यह सर्वर से अनुरोध भेजता है और जब यह प्रतीक्षा करता है, तो तुरंत एक jQuery अजाक्स डिफरर्ड ऑब्जेक्ट देता है, प्रतिक्रिया नहीं सर्वर। इसका मतलब है कि if कथन हमेशा इस डिफर्ड ऑब्जेक्ट को प्राप्त करने जा रहा है, तो इसे true मानें, और आगे बढ़ें जैसे कि उपयोगकर्ता लॉग इन है। अच्छा नहीं।

लेकिन फिक्स आसान है:

checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});

अनुशंसित नहीं: सिंक्रोनस "अजाक्स" कॉल

जैसा कि मैंने उल्लेख किया है, कुछ (!) एसिंक्रोनस ऑपरेशंस में समकालिक समकक्ष हैं। मैं उनके उपयोग की वकालत नहीं करता हूं, लेकिन पूर्णता के लिए, यहां एक सिंक्रोनस कॉल करने का तरीका बताया गया है:

JQuery के बिना

यदि आप सीधे XMLHTTPRequest ऑब्जेक्ट का उपयोग करते हैं, तो तीसरे तर्क के रूप में false पास करें। .open

jQuery

यदि आप jQuery उपयोग करते हैं, तो आप async विकल्प को false सेट कर सकते हैं। ध्यान दें कि यह विकल्प jQuery 1.8 के बाद से बहिष्कृत है । फिर भी आप success कॉलबैक का उपयोग कर सकते हैं या responseText उपयोग कर सकते हैं jqXHR ऑब्जेक्ट की टेक्स्ट गुण:

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

यदि आप $.get , $.getJSON , आदि जैसे किसी भी अन्य jQuery अजाक्स विधि का उपयोग करते हैं, तो आपको इसे $.ajax बदलना होगा (क्योंकि आप केवल कॉन्फ़िगरेशन पैरामीटर को $.ajax पास कर सकते हैं)।

सचेत! एक तुल्यकालिक JSONP अनुरोध करना संभव नहीं है। JSONP अपनी प्रकृति से हमेशा असीमित है (इस विकल्प को भी मानने का एक और कारण नहीं है)।


जेएस एक धागा है।

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

1) घटना लूप

2) वेब एपीआई

3) घटना कतार

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

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

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

इस प्रकार यह करने के लिए समाधान है कॉलबैक या वादा

यहां दिए गए उत्तरों में से एक छवि, कॉलबैक उपयोग को सही ढंग से बताती है ... हम फ़ंक्शन कॉलिंग सर्वर पर हमारे फ़ंक्शन (सर्वर से लौटाए गए डेटा का उपयोग करते हुए फ़ंक्शन) देते हैं।

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}

मेरे संहिता में इसे कहा जाता है

function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}

एसिमा कॉल करने के लिए ईसीएमए (2016/17) में नई विधियों के लिए यहां पढ़ें (शीर्ष पर @ फ़ेलिक्स क्लिंग उत्तर) https://.com/a/14220323/7579856


यदि आप वादे का उपयोग कर रहे हैं, तो यह जवाब आपके लिए है।

इसका मतलब है AngularJS, jQuery (स्थगित के साथ), देशी एक्सएचआर का प्रतिस्थापन (fetch), एम्बरजेएस, बैकबोनजेएस की बचत या कोई भी नोड लाइब्रेरी जो वादे देता है।

आपका कोड इस तरह के साथ कुछ होना चाहिए:

function foo() {
    var data;
    // or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // result is always undefined no matter what.

फ़ेलिक्स क्लिंग ने AJAX के लिए कॉलबैक के साथ jQuery का उपयोग करने वाले लोगों के लिए एक उत्तर लिखने का एक अच्छा काम किया। मेरे पास देशी एक्सएचआर का जवाब है। यह उत्तर फ्रंटेंड या बैकएंड पर या तो वादे के सामान्य उपयोग के लिए है।

मुख्य मुद्दा

ब्राउजर में जावास्क्रिप्ट समरूपता मॉडल और सर्वर पर नोडजेएस / io.js के साथ असीमित और प्रतिक्रियाशील है

जब भी आप एक ऐसी विधि को कॉल करते हैं जो वादा करता है, तो then हैंडलर हमेशा असीमित रूप से निष्पादित होते हैं - यानी, उनके नीचे दिए गए कोड के बाद .then हैंडलर में नहीं है।

इसका अर्थ यह है कि जब आप data लौट रहे हैं then आपके द्वारा परिभाषित किए गए हैंडलर को अभी तक निष्पादित नहीं किया गया है। बदले में इसका मतलब है कि आप जिस मूल्य को वापस कर रहे हैं उसे समय पर सही मूल्य पर सेट नहीं किया गया है।

इस मुद्दे के लिए यहां एक सरल सादृश्य है:

    function getFive(){
        var data;
        setTimeout(function(){ // set a timer for one second in the future
           data = 5; // after a second, do this
        }, 1000);
        return data;
    }
    document.body.innerHTML = getFive(); // `undefined` here and not 5

data का मान undefined क्योंकि data = 5 भाग अभी तक निष्पादित नहीं हुआ है। यह संभवतः एक सेकंड में निष्पादित होगा लेकिन उस समय तक यह लौटा मूल्य के लिए अप्रासंगिक है।

चूंकि ऑपरेशन अभी तक नहीं हुआ है (AJAX, सर्वर कॉल, आईओ, टाइमर) अनुरोध से पहले आप मान को वापस कर रहे हैं कि आपके कोड को यह बताने का मौका मिला कि वह मूल्य क्या है।

इस समस्या का एक संभावित समाधान कोड को सक्रिय रूप से कोड करना है, यह बताएं कि गणना पूरी होने पर आपके प्रोग्राम को क्या करना है। वादे सक्रिय रूप से प्रकृति में अस्थायी (समय-संवेदनशील) होने के द्वारा सक्रिय रूप से सक्षम करते हैं।

वादे पर त्वरित पुनरावृत्ति

एक वादा समय के साथ एक मूल्य है । वादे के पास राज्य है, वे बिना किसी मूल्य के लंबित हैं और इस पर व्यवस्थित हो सकते हैं:

  • पूरा अर्थ है कि गणना सफलतापूर्वक पूर्ण हो गई।
  • अस्वीकार कर दिया गया कि गणना विफल रही।

एक वादा केवल राज्यों को बदल सकता है जिसके बाद यह हमेशा के लिए एक ही राज्य में हमेशा रहेगा। आप then हैंडलर को अपने मूल्य निकालने और त्रुटियों को संभालने का वादा करने के लिए संलग्न कर सकते हैं। then हैंडलर कॉल की chaining की अनुमति देते हैं। वादे उन एपीआई का उपयोग करके बनाए जाते हैं जो उन्हें वापस कर देते हैं । उदाहरण के लिए, अधिक आधुनिक AJAX प्रतिस्थापन fetch या jQuery का $.get वापसी का वादा करता है।

जब हम कॉल करते हैं। .then एक वादे पर और इससे कुछ वापस लौटें - हमें संसाधित मूल्य के लिए एक वादा मिलता है। अगर हम एक और वादा वापस करते हैं तो हमें अद्भुत चीजें मिलेंगी, लेकिन चलो अपने घोड़ों को पकड़ें।

वादे के साथ

चलो देखते हैं कि हम ऊपर दिए गए मुद्दे को वादे के साथ कैसे हल कर सकते हैं। सबसे पहले, विलंब समारोह बनाने के लिए वादा कन्स्ट्रक्टर का उपयोग करके ऊपर से वादे राज्यों की हमारी समझ का प्रदर्शन करते हैं:

function delay(ms){ // takes amount of milliseconds
    // returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // when the time is up
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

अब, हमने सेटटाइमआउट को वादे का उपयोग करने के लिए परिवर्तित करने के बाद, हम thenइसे गिनने के लिए उपयोग कर सकते हैं :

function delay(ms){ // takes amount of milliseconds
  // returns a new promise
  return new Promise(function(resolve, reject){
    setTimeout(function(){ // when the time is up
      resolve(); // change the promise to the fulfilled state
    }, ms);
  });
}

function getFive(){
  // we're RETURNING the promise, remember, a promise is a wrapper over our value
  return delay(100).then(function(){ // when the promise is ready
      return 5; // return the value 5, promises are all about return values
  })
}
// we _have_ to wrap it like this in the call site, we can't access the plain value
getFive().then(function(five){ 
   document.body.innerHTML = five;
});

मूल रूप से, एक लौटने के बजाय मूल्य है जो हम क्योंकि संगामिति मॉडल के लिए नहीं कर सकते हैं - हम एक लौट रहे हैं आवरण एक मूल्य है कि हम कर सकते हैं के लिए खोलने के साथ then। यह एक बॉक्स की तरह है जिसे आप खोल सकते हैं then

इसे लागू करना

यह आपके मूल एपीआई कॉल के लिए समान है, आप यह कर सकते हैं:

function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // process it inside the `then`
    });
}

foo().then(function(response){
    // access the value inside the `then`
})

तो यह भी काम करता है। हमने सीखा है कि हम पहले से ही असीमित कॉल से मूल्य वापस नहीं कर सकते हैं, लेकिन हम वादे का उपयोग कर सकते हैं और प्रसंस्करण करने के लिए उन्हें चेन कर सकते हैं। अब हम जानते हैं कि एसिंक्रोनस कॉल से प्रतिक्रिया कैसे वापस करनी है।

ES2015 (ES6)

ईएस 6 generators पेश करता generators जो कि फ़ंक्शन हैं जो बीच में वापस आ सकते हैं और फिर उस बिंदु को फिर से शुरू कर सकते हैं। यह आमतौर पर अनुक्रमों के लिए उपयोगी है, उदाहरण के लिए:

function* foo(){ // notice the star, this is ES6 so new browsers/node/io only
    yield 1;
    yield 2;
    while(true) yield 3;
}

एक ऐसा फ़ंक्शन है जो अनुक्रम पर एक पुनरावर्तक देता है 1,2,3,3,3,3,....जिसे पुनरावृत्त किया जा सकता है। हालांकि यह अपने आप में दिलचस्प है और बहुत संभावना के लिए कमरा खोलता है, एक विशेष दिलचस्प मामला है।

यदि हम जिस क्रम का उत्पादन कर रहे हैं वह संख्याओं की बजाय क्रियाओं का अनुक्रम है - जब भी कोई कार्यवाही की जाती है तो हम फ़ंक्शन को रोक सकते हैं और फ़ंक्शन को फिर से शुरू करने से पहले इसके लिए प्रतीक्षा कर सकते हैं। तो संख्याओं के क्रम के बजाय, हमें भविष्य के मूल्यों के अनुक्रम की आवश्यकता है - वह है: वादे।

यह कुछ हद तक मुश्किल लेकिन बहुत शक्तिशाली चाल हमें सिंक्रोनस तरीके से एसिंक्रोनस कोड लिखने देता है। कई "धावक" हैं जो आपके लिए यह करते हैं, एक लिखना कोड की एक छोटी सी रेखा है लेकिन इस उत्तर के दायरे से बाहर है। मैं Promise.coroutineयहां ब्लूबर्ड का उपयोग करूँगा , लेकिन अन्य रैपर जैसे coया हैं Q.async

var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // notice the yield
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
});

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

var main = coroutine(function*(){
   var bar = yield foo(); // wait our earlier coroutine, it returns a promise
   // server call done here, code below executes when done
   var baz = yield fetch("/api/users/"+bar.userid); // depends on foo's result
   console.log(baz); // runs after both requests done
});
main();

ES2016 (ES7)

ईएस 7 में, यह और मानकीकृत है, अभी कई प्रस्ताव हैं लेकिन उनमें से सभी आप awaitवादा कर सकते हैं । यह ऊपर और ईएस 6 प्रस्ताव के लिए ऊपर "चीनी" (nicer वाक्यविन्यास) है asyncऔर awaitकीवर्ड जोड़कर । उपरोक्त उदाहरण बनाना:

async function foo(){
    var data = await fetch("/echo/json"); // notice the await
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
}

यह अभी भी वही वचन देता है :)


2017 उत्तर: अब आप वही कर सकते हैं जो आप हर मौजूदा ब्राउज़र और नोड में चाहते हैं

यह काफी सरल है:

  • एक वादा वापस करो
  • await प्रयोग करें , जो जावास्क्रिप्ट को एक मूल्य में हल करने के वादे का इंतजार करने के लिए बताएगा (जैसे HTTP प्रतिक्रिया)
  • पैरेंट फ़ंक्शन में async/await कीवर्ड जोड़ें

यहां आपके कोड का एक वर्किंग वर्जन है:

(async function(){

var response = await superagent.get('...')
console.log(response)

})()

प्रतीक्षा सभी मौजूदा ब्राउज़रों और नोड 8 में समर्थित है


एसिंक्रोनस अनुरोधों के साथ काम करने के कुछ दृष्टिकोण यहां दिए गए हैं:

  1. then()
  2. Q - जावास्क्रिप्ट के लिए एक वादा पुस्तकालय
  3. ए + Promises.js
  4. jQuery स्थगित
  5. XMLHttpRequest API
  6. कॉलबैक अवधारणा का उपयोग करना - पहले जवाब में कार्यान्वयन के रूप में

उदाहरण: एकाधिक अनुरोधों के साथ काम करने के लिए jQuery स्थगित कार्यान्वयन

var App = App || {};

App = {
    getDataFromServer: function(){

      var self = this,
                 deferred = $.Deferred(),
                 requests = [];

      requests.push($.getJSON('request/ajax/url/1'));
      requests.push($.getJSON('request/ajax/url/2'));

      $.when.apply(jQuery, requests).done(function(xhrResponse) {
        return deferred.resolve(xhrResponse.result);
      });
      return deferred;
    },

    init: function(){

        this.getDataFromServer().done(_.bind(function(resp1, resp2) {

           // Do the operations which you wanted to do when you
           // get a response from Ajax, for example, log response.
        }, this));
    }
};
App.init();


XMLHttpRequest 2 (सबसे पहले बेंजामिन ग्रुनेबाम और फ़ेलिक्स क्लिंग के उत्तरों को पढ़ें)

यदि आप jQuery का उपयोग नहीं करते हैं और एक अच्छा छोटा XMLHttpRequest 2 चाहते हैं जो आधुनिक ब्राउज़र पर और मोबाइल ब्राउज़र पर भी काम करता है तो मैं इसे इस तरह उपयोग करने का सुझाव देता हूं:

function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

जैसा कि आप देख सकते हैं:

  1. यह सूचीबद्ध अन्य सभी कार्यों की तुलना में छोटा है।
  2. कॉलबैक सीधे सेट है (इसलिए कोई अतिरिक्त अनावश्यक बंद)।
  3. यह नए अधिभार का उपयोग करता है (इसलिए आपको तैयार करने और स्थिति की जांच करने की आवश्यकता नहीं है)
  4. ऐसी कुछ अन्य स्थितियां हैं जिन्हें मुझे याद नहीं है जो XMLHttpRequest 1 परेशान करते हैं।

इस अजाक्स कॉल की प्रतिक्रिया प्राप्त करने के दो तरीके हैं (XMLHttpRequest var नाम का उपयोग करके तीन):

सबसे साधारण:

this.response

या अगर किसी कारण से आप कक्षा में कॉलबैक bind() :

e.target.response

उदाहरण:

function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

या (उपर्युक्त एक बेहतर अज्ञात कार्य हमेशा एक समस्या है):

ajax('URL', function(e){console.log(this.response)});

कुछ भी आसान नहीं है।

अब कुछ लोग शायद कहेंगे कि पहले से हीस्टेन्चेंज या यहां तक ​​कि XMLHttpRequest चर नाम का उपयोग करना बेहतर है। यह गलत है।

XMLHttpRequest उन्नत सुविधाओं को देखें

यह सभी * आधुनिक ब्राउज़रों पर समर्थित है। और मैं पुष्टि कर सकता हूं क्योंकि मैं इस दृष्टिकोण का उपयोग कर रहा हूं क्योंकि XMLHttpRequest 2 मौजूद है। मेरे द्वारा उपयोग किए जाने वाले सभी ब्राउज़रों पर मुझे कभी भी कोई समस्या नहीं थी।

onreadystatechange केवल तभी उपयोगी होता है जब आप हेडर को राज्य 2 पर प्राप्त करना चाहते हैं।

XMLHttpRequest चर नाम का उपयोग करना एक और बड़ी त्रुटि है क्योंकि आपको ऑनलोड / oreadystatechange बंद करने के अंदर कॉलबैक निष्पादित करने की आवश्यकता है, जिसे आपने खो दिया है।

अब यदि आप पोस्ट और फॉर्मडाटा का उपयोग करके कुछ और जटिल चाहते हैं तो आप आसानी से इस फ़ंक्शन को बढ़ा सकते हैं:

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.send(d||null)
}

दोबारा ... यह एक बहुत छोटा काम है, लेकिन यह मिलता है और पोस्ट करता है।

उपयोग के उदाहरण:

x(url, callback); // By default it's get so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set post data

या एक पूर्ण फॉर्म तत्व पास करें ( document.getElementsByTagName('form')[0] ):

var fd = new FormData(form);
x(url, callback, 'post', fd);

या कुछ कस्टम मान सेट करें:

var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

जैसा कि आप देख सकते हैं कि मैंने सिंक लागू नहीं किया है ... यह एक बुरी बात है।

ऐसा कहकर ... यह आसान तरीका क्यों नहीं करते?

जैसा कि टिप्पणी में बताया गया है त्रुटि और तुल्यकालिक का उपयोग पूरी तरह से उत्तर के बिंदु को तोड़ देता है। उचित तरीके से अजाक्स का उपयोग करने का एक अच्छा छोटा तरीका कौन सा है?

त्रुटि हैंडलर

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.onerror = error;
  c.send(d||null)
}

function error(e){
  console.log('--Error--', this.type);
  console.log('this: ', this);
  console.log('Event: ', e)
}
function displayAjax(e){
  console.log(e, this);
}
x('WRONGURL', displayAjax);

उपर्युक्त स्क्रिप्ट में, आपके पास एक त्रुटि हैंडलर है जिसे स्थिर रूप से परिभाषित किया गया है, इसलिए यह फ़ंक्शन से समझौता नहीं करता है। त्रुटि हैंडलर अन्य कार्यों के लिए भी इस्तेमाल किया जा सकता है।

लेकिन वास्तव में एक त्रुटि प्राप्त करने के लिए एक गलत तरीका एक गलत यूआरएल लिखना है जिसमें हर ब्राउज़र एक त्रुटि फेंकता है।

यदि आप कस्टम हेडर सेट करते हैं, तो त्रुटि हैंडलर उपयोगी हो सकते हैं, प्रतिक्रिया सेट करें ब्लॉब सरणी बफर या जो कुछ भी ....

यहां तक ​​कि यदि आप विधि के रूप में 'POSTAPAPAP' पास करते हैं तो यह कोई त्रुटि नहीं फेंक देगा।

भले ही आप 'fdggdgilfdghfldj' को फॉर्मडाटा के रूप में पास करते हैं, यह एक त्रुटि नहीं फेंक देगा।

पहले मामले में त्रुटि displayAjax() के अंदर है। इस Method not Allowed तहत this.statusText को Method not Allowed गई Method not Allowed रूप में।

दूसरे मामले में, यह बस काम करता है। यदि आपने सही पोस्ट डेटा पास किया है तो आपको सर्वर की ओर से जांच करनी होगी।

क्रॉस-डोमेन की अनुमति नहीं है स्वचालित रूप से त्रुटि फेंकता है।

त्रुटि प्रतिक्रिया में, कोई त्रुटि कोड नहीं हैं।

केवल यही है। this.type जो त्रुटि पर सेट है।

अगर आप त्रुटियों पर पूरी तरह से नियंत्रण नहीं रखते हैं तो एक त्रुटि हैंडलर क्यों जोड़ें? कॉलबैक फ़ंक्शन displayAjax() अधिकांश त्रुटियों को इसके अंदर वापस कर दिया जाता है।

इसलिए: यदि आप URL को कॉपी और पेस्ट करने में सक्षम हैं तो त्रुटि जांच की कोई आवश्यकता नहीं है। ;)

पीएस: पहले परीक्षण के रूप में मैंने एक्स ('एक्स', डिस्प्लेएजेक्स) लिखा ..., और इसे पूरी तरह से प्रतिक्रिया मिली ... ??? इसलिए मैंने उस फ़ोल्डर को चेक किया जहां HTML स्थित है, और 'x.xml' नामक एक फ़ाइल थी। तो अगर आप अपनी फ़ाइल का विस्तार भूल जाते हैं तो XMLHttpRequest 2 इसे ढूंढ जाएगा । मैंने लोल किया

एक फ़ाइल तुल्यकालिक पढ़ें

ऐसा मत करो।

यदि आप थोड़ी देर के लिए ब्राउज़र को अवरुद्ध करना चाहते हैं तो एक अच्छी बड़ी txt फ़ाइल तुल्यकालिक लोड करें।

function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

अब आप कर सकते हैं

 var res = omg('thisIsGonnaBlockThePage.txt');

गैर-असीमित तरीके से ऐसा करने का कोई और तरीका नहीं है। (हाँ, setTimeout पाश के साथ ... लेकिन गंभीरता से?)

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

केवल तभी यदि आपके पास एक ऐसा पृष्ठ है जहां आप हमेशा एक ही एक्सएमएल / जेएसओएन लोड करते हैं या जो कुछ भी आपको केवल एक समारोह की आवश्यकता होती है। उस स्थिति में, थोड़ा अजाक्स फ़ंक्शन संशोधित करें और अपने विशेष फ़ंक्शन के साथ बी को प्रतिस्थापित करें।

ऊपर दिए गए कार्य बुनियादी उपयोग के लिए हैं।

यदि आप फ़ंक्शन को विस्तारित करना चाहते हैं ...

हाँ तुम कर सकते हो।

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

लेकिन आप XMLHttpRequest 2 के साथ बहुत सारी चीज़ें कर सकते हैं:

मैंने एक डाउनलोड मैनेजर (रेज़्यूम, फाइलreader, फाइल सिस्टम के साथ दोनों तरफ श्रेणियों का उपयोग करके), कैनवास का उपयोग कर विभिन्न छवि रेजिज़र कन्वर्टर्स, बेस 64images के साथ websql डेटाबेस पॉप्युलेट और बहुत कुछ ... लेकिन इन मामलों में आपको केवल उस उद्देश्य के लिए एक फ़ंक्शन बनाना चाहिए ... कभी-कभी आपको ब्लॉब, सरणी बफर की आवश्यकता होती है, आप हेडर सेट कर सकते हैं, माइमटाइप ओवरराइड कर सकते हैं और बहुत कुछ है ...

लेकिन यहां सवाल यह है कि अजाक्स प्रतिक्रिया कैसे वापस करनी है ... (मैंने एक आसान तरीका जोड़ा।)


पेड़ को देखने से पहले जंगल को पहले देखते हैं।

यहां महान विवरण के साथ कई सूचनात्मक उत्तर हैं, मैं उनमें से किसी को दोहराना नहीं चाहूंगा। जावास्क्रिप्ट में प्रोग्रामिंग की कुंजी पहले निष्पादन का सही मानसिक मॉडल है।

  1. आपके प्रविष्टि बिंदु को किसी ईवेंट के परिणामस्वरूप निष्पादित किया जाता है। उदाहरण के लिए, ब्राउज़र में कोड के साथ एक स्क्रिप्ट टैग लोड किया जाता है। (तदनुसार, यही कारण है कि आपको अपने कोड को चलाने के लिए पृष्ठ की तत्परता से चिंतित होने की आवश्यकता हो सकती है यदि इसे पहले डोम तत्वों का निर्माण करने की आवश्यकता होती है)
  2. आपका कोड पूरा होने के लिए निष्पादित करता है - हालांकि कई एसिंक्रोनस कॉल करता है - आपके किसी भी कॉलबैक को निष्पादित किए बिना , एक्सएचआर अनुरोधों सहित, टाइमआउट्स, डोम इवेंट हैंडलर आदि सेट करें। इनमें से प्रत्येक कॉलबैक निष्पादित होने का इंतजार कर रहा है, प्रतीक्षा कर रहा है, प्रतीक्षा कर रहा है निकाल दिया गया अन्य घटनाओं के बाद उनकी बारी को चलाने के लिए सभी निष्पादन समाप्त हो गया है।
  3. एक एक्सएचआर अनुरोध के लिए प्रत्येक व्यक्तिगत कॉलबैक, टाइमआउट या डोम सेट एक बार लागू होने वाली घटना को पूरा करने के लिए चलाया जाएगा।

अच्छी खबर यह है कि यदि आप इस बिंदु को अच्छी तरह समझते हैं, तो आपको दौड़ की स्थिति के बारे में चिंता करने की ज़रूरत नहीं होगी। आपको सबसे पहले और सबसे महत्वपूर्ण बात यह है कि आप अपने कोड को अनिवार्य रूप से विभिन्न अलग-अलग घटनाओं के जवाब के रूप में व्यवस्थित करना चाहते हैं, और आप उन्हें एक तार्किक अनुक्रम में कैसे थ्रेड करना चाहते हैं। आप वादे या उच्च स्तर के नए एसिंक / उस अंत तक उपकरण के रूप में प्रतीक्षा कर सकते हैं, या आप अपना खुद का रोल कर सकते हैं।

लेकिन जब तक आप वास्तविक समस्या डोमेन से सहज नहीं हैं तब तक आपको किसी समस्या को हल करने के लिए किसी भी सामरिक उपकरण का उपयोग नहीं करना चाहिए। यह निर्भर करने के लिए कि इन्हें चलाने की आवश्यकता है, इन निर्भरताओं का नक्शा बनाएं। इन सभी कॉलबैक के लिए एक विज्ञापन-प्रसार दृष्टिकोण का प्रयास करना सिर्फ आपकी सेवा करने वाला नहीं है।


संक्षिप्त उत्तर : आपकी foo()विधि तत्काल लौटती है, जबकि फ़ंक्शन रिटर्न के बाद$ajax() कॉल असीमित रूप से निष्पादित करता है । समस्या तब होती है जब यह लौटने के बाद एसिंक कॉल द्वारा पुनर्प्राप्त परिणामों को कैसे या कहां स्टोर किया जाए।

इस धागे में कई समाधान दिए गए हैं। शायद ऑब्जेक्ट को foo()विधि में पास करने का सबसे आसान तरीका है , और एसिंक कॉल पूर्ण होने के बाद परिणामों को उस ऑब्जेक्ट के सदस्य में संग्रहीत करना है।

function foo(result) {
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;   // Store the async result
        }
    });
}

var result = { response: null };   // Object to hold the async result
foo(result);                       // Returns before the async completes

ध्यान दें कि कॉल foo()अभी भी कुछ भी उपयोगी नहीं होगा। हालांकि, async कॉल का परिणाम अब संग्रहीत किया जाएगा result.response


ईसीएमएस्क्रिप्ट 6 में 'जनरेटर' हैं जो आपको आसानी से एक असीमित शैली में प्रोग्राम करने की अनुमति देते हैं।

function* myGenerator() {
    const callback = yield;
    let [response] = yield $.ajax("https://.com", {complete: callback});
    console.log("response is:", response);

    // examples of other things you can do
    yield setTimeout(callback, 1000);
    console.log("it delayed for 1000ms");
    while (response.statusText === "error") {
        [response] = yield* anotherGenerator();
    }
}

उपर्युक्त कोड चलाने के लिए आप यह करते हैं:

const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function

यदि आपको ऐसे ब्राउज़र को लक्षित करने की आवश्यकता है जो ईएस 6 का समर्थन नहीं करते हैं तो आप ईसीएमएस्क्रिप्ट 5 उत्पन्न करने के लिए बेबेल या क्लोजर-कंपाइलर के माध्यम से कोड चला सकते हैं।

कॉलबैक ...argsएक सरणी में लपेटा जाता है और जब आप उन्हें पढ़ते हैं तो नष्ट हो जाता है ताकि पैटर्न कॉलबैक से निपट सके जो कई तर्क हैं। उदाहरण के लिए नोड एफएस के साथ :

const [err, data] = yield fs.readFile(filePath, "utf-8", callback);

एक एसिंक्रोनस फ़ंक्शन से मूल्य वापस करने का एक और तरीका, किसी ऑब्जेक्ट में पास करना है जो परिणाम को एसिंक्रोनस फ़ंक्शन से संग्रहीत करेगा।

यहां इसका एक उदाहरण दिया गया है:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

मैं resultएसिंक्रोनस ऑपरेशन के दौरान मूल्य को स्टोर करने के लिए ऑब्जेक्ट का उपयोग कर रहा हूं । यह परिणाम असीमित काम के बाद भी उपलब्ध हो सकता है।

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


मैंने जो उदाहरण दिया है, वह दिखाता है कि कैसे करें

  • एसिंक्रोनस HTTP कॉल को संभाल लें;
  • प्रत्येक एपीआई कॉल से प्रतिक्रिया के लिए प्रतीक्षा करें;
  • Promise पैटर्न का प्रयोग करें ;
  • एकाधिक HTTP कॉल में शामिल होने के लिए Promise.All पैटर्न का उपयोग करें;

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

प्रसंग। उदाहरण क्वेरी स्ट्रिंग्स के दिए गए सेट के लिए ऑब्जेक्ट्स को खोजने के लिए स्पॉटिफा वेब एपीआई एंडपॉइंट से पूछताछ कर रहा है playlist:

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

प्रत्येक आइटम के लिए, एक नया वादा एक ब्लॉक को आग लगाएगा - ExecutionBlockपरिणाम को पार्स करेगा, परिणाम सरणी के आधार पर वादे का एक नया सेट शेड्यूल करेगा, यह Spotify userऑब्जेक्ट्स की एक सूची है और नई HTTP कॉल को ExecutionProfileBlockअसीमित रूप से निष्पादित करता है ।

फिर आप एक नेस्टेड वादा संरचना देख सकते हैं, जो आपको एकाधिक और पूरी तरह से एसिंक्रोनस नेस्टेड HTTP कॉलों को जन्म देता है, और कॉल के प्रत्येक उप-समूह से परिणामों में शामिल हो सकता है Promise.all

नोट हालिया Spotify searchAPI को अनुरोध हेडर में निर्दिष्ट करने के लिए एक्सेस टोकन की आवश्यकता होगी:

-H "Authorization: Bearer {your access token}" 

तो, आप निम्न उदाहरण को चलाने के लिए अनुरोध हेडर में अपना एक्सेस टोकन डालने की आवश्यकता है:

var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "<br/>"
    }
}

// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
    call: function(what, response) {
        var request;
        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // Internet Explorer
            try {
                request = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
                try {
                  request = new ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {}
            }
        }

        // State changes
        request.onreadystatechange = function() {
            if (request.readyState === 4) { // Done
                if (request.status === 200) { // Complete
                    response(request.responseText)
                }
                else
                    response();
            }
        }
        request.open('GET', what, true);
        request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
        request.send(null);
    }
}

//PromiseAll
var promiseAll = function(items, block, done, fail) {
    var self = this;
    var promises = [],
                   index = 0;
    items.forEach(function(item) {
        promises.push(function(item, i) {
            return new Promise(function(resolve, reject) {
                if (block) {
                    block.apply(this, [item, index, resolve, reject]);
                }
            });
        }(item, ++index))
    });
    Promise.all(promises).then(function AcceptHandler(results) {
        if (done) done(results);
    }, function ErrorHandler(error) {
        if (fail) fail(error);
    });
}; //promiseAll

// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
    var url = "https://api.spotify.com/v1/"
    url += item;
    console.log( url )
    SimpleRequest.call(url, function(result) {
        if (result) {

            var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
                return item.owner.href;
            })
            resolve(profileUrls);
        }
        else {
            reject(new Error("call error"));
        }
    })
}

arr = [
    "search?type=playlist&q=%22doom%20metal%22",
    "search?type=playlist&q=Adele"
]

promiseAll(arr, function(item, index, resolve, reject) {
    console.log("Making request [" + index + "]")
    ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results

    console.log("All profiles received " + results.length);
    //console.log(JSON.stringify(results[0], null, 2));

    ///// promiseall again

    var ExecutionProfileBlock = function(item, index, resolve, reject) {
        SimpleRequest.call(item, function(result) {
            if (result) {
                var obj = JSON.parse(result);
                resolve({
                    name: obj.display_name,
                    followers: obj.followers.total,
                    url: obj.href
                });
            } //result
        })
    } //ExecutionProfileBlock

    promiseAll(results[0], function(item, index, resolve, reject) {
        //console.log("Making request [" + index + "] " + item)
        ExecutionProfileBlock(item, index, resolve, reject);
    }, function(results) { // aggregated results
        console.log("All response received " + results.length);
        console.log(JSON.stringify(results, null, 2));
    }

    , function(error) { // Error
        console.log(error);
    })

    /////

  },
  function(error) { // Error
      console.log(error);
  });
<div id="console" />

मैंने इस समाधान पर व्यापक रूप से चर्चा की here


रिमोट कॉल करने के लिए आप इस कस्टम लाइब्रेरी (वादा का उपयोग करके लिखित) का उपयोग कर सकते हैं।

function $http(apiConfig) {
    return new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open(apiConfig.method, apiConfig.url);
        client.send();
        client.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                // Performs the function "resolve" when this.status is equal to 2xx.
                // Your logic here.
                resolve(this.response);
            }
            else {
                // Performs the function "reject" when this.status is different than 2xx.
                reject(this.statusText);
            }
        };
        client.onerror = function () {
            reject(this.statusText);
        };
    });
}

सरल उपयोग उदाहरण:

$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});

आप अजाक्स का गलत इस्तेमाल कर रहे हैं। विचार यह है कि यह कुछ भी वापस नहीं लेना है, बल्कि डेटाबैक फ़ंक्शन नामक किसी चीज़ को डेटा बंद कर दें, जो डेटा को संभालता है।

अर्थात्:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

सबमिट हैंडलर में कुछ भी लौटाना कुछ भी नहीं करेगा। आपको इसके बजाय डेटा को हाथ से बंद करना होगा, या सफलता कार्य के अंदर सीधे इसके साथ जो करना चाहते हैं उसे करें।


आप पर कोड फेंकने की बजाय, 2 अवधारणाएं हैं जो समझने के लिए महत्वपूर्ण हैं कि जेएस कॉलबैक और असिंक्रोनिटी को कैसे प्रबंधित करता है। (क्या यह एक शब्द भी है?)

इवेंट लूप और कंसुरेंसी मॉडल

ऐसी तीन चीजें हैं जिनके बारे में आपको अवगत होना चाहिए; कतार; घटना पाश और ढेर

विस्तृत, सरल शब्दों में, इवेंट लूप प्रोजेक्ट मैनेजर की तरह है, यह लगातार किसी भी फ़ंक्शन को सुन रहा है जो कतार और स्टैक के बीच चलना और संचार करना चाहता है।

while (queue.waitForMessage()) {
   queue.processNextMessage();
}

एक बार यह कुछ चलाने के लिए एक संदेश प्राप्त हो जाता है, यह इसे कतार में जोड़ता है। कतार उन चीज़ों की सूची है जो निष्पादित करने की प्रतीक्षा कर रहे हैं (जैसे आपके AJAX अनुरोध)। इसे इस तरह कल्पना करें:

 1. call foo.com/api/bar using foobarFunc
 2. Go perform an infinite loop
 ... and so on

जब इनमें से एक संदेश निष्पादित करने जा रहा है, तो यह कतार से संदेश पॉप करता है और एक ढेर बनाता है, स्टैक सब कुछ जेएस को संदेश में निर्देश करने के लिए निष्पादित करने की आवश्यकता है। तो हमारे उदाहरण में इसे कॉल करने के लिए कहा जा रहा हैfoobarFunc

function foobarFunc (var) {
  console.log(anotherFunction(var));
}

तो कुछ भी जो foobarFunc को निष्पादित करने की आवश्यकता है (हमारे मामले में anotherFunction) ढेर पर धकेल दिया जाएगा। निष्पादित, और फिर भूल गया - घटना लूप फिर कतार में अगली चीज़ पर चलेगा (या संदेशों के लिए सुनो)

यहां मुख्य बात निष्पादन का आदेश है। अर्थात्

कब चलने वाला कुछ है

जब आप किसी बाहरी पार्टी में AJAX का उपयोग करके कॉल करते हैं या किसी भी एसिंक्रोनस कोड (उदाहरण के लिए सेटटाइमआउट) चलाते हैं, तो जावास्क्रिप्ट आगे बढ़ने से पहले प्रतिक्रिया पर निर्भर होता है।

बड़ा सवाल यह है कि यह प्रतिक्रिया कब मिलेगी? जवाब यह है कि हम नहीं जानते हैं - इसलिए इवेंट लूप उस संदेश के लिए इंतजार कर रहा है कि "अरे मुझे चलाएं"। अगर जेएस बस उस संदेश के लिए सिंक्रनाइज़ रूप से इंतजार कर रहा था तो आपका ऐप स्थिर हो जाएगा और यह चूस जाएगा। तो जेएस कतार में वापस जोड़ने के लिए प्रतीक्षा करते हुए कतार में अगले आइटम को निष्पादित करने पर चलता है।

यही कारण है कि एसिंक्रोनस कार्यक्षमता के साथ हम कॉलबैक नामक चीजों का उपयोग करते हैं । यह सचमुच एक then() तरह है । जैसा कि मैं किसी बिंदु पर कुछ वापस करने का वादा करता हूं, jQuery विशिष्ट कॉलबैक का उपयोग करता है deffered.done deffered.failऔर deffered.always(दूसरों के बीच)। आप उन्हें here सब देख सकते हैंhere

तो आपको जो करने की ज़रूरत है वह एक ऐसा फ़ंक्शन पास करता है जिसे किसी बिंदु पर निष्पादित करने के लिए वादा किया जाता है।

चूंकि कॉलबैक तुरंत निष्पादित नहीं होता है लेकिन बाद में फ़ंक्शन के संदर्भ को पारित करना महत्वपूर्ण नहीं होता है। इसलिए

function foo(bla) {
  console.log(bla)
}

तो अधिकांश समय (लेकिन हमेशा नहीं) आप पास fooनहीं करेंगेfoo()

उम्मीद है कि कुछ समझ में आ जाएगा। जब आप इस तरह की चीजों का सामना करते हैं जो उलझन में लगते हैं - मैं अत्यधिक दस्तावेज़ीकरण को पढ़ने की सलाह देता हूं ताकि कम से कम इसे समझ सकें। यह आपको एक बेहतर डेवलपर बना देगा।


जावास्क्रिप्ट के 'रहस्य' के साथ संघर्ष करते समय हम एक बहुत ही आम समस्या का सामना करते हैं। मुझे आज इस रहस्य को नष्ट करने का प्रयास करें।

आइए एक साधारण जावास्क्रिप्ट फ़ंक्शन से शुरू करें:

function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here

यह एक सरल सिंक्रोनस फ़ंक्शन कॉल है (जहां कोड की प्रत्येक पंक्ति अनुक्रम में अगले एक से पहले 'अपनी नौकरी के साथ समाप्त होती है), और परिणाम अपेक्षित के समान होता है।

आइए अब हमारे फ़ंक्शन में थोड़ी देर देरी करके, थोड़ा मोड़ जोड़ें, ताकि कोड की सभी पंक्तियां अनुक्रम में 'समाप्त' न हों। इस प्रकार, यह कार्य के असीमित व्यवहार का अनुकरण करेगा:

function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

तो वहां आप जाते हैं, उस देरी ने हमारी कार्यक्षमता को तोड़ दिया! लेकिन वास्तव में क्या हुआ? खैर, अगर आप कोड देखते हैं तो यह वास्तव में बहुत तार्किक है। फ़ंक्शन foo(), निष्पादन पर, कुछ भी नहीं लौटाता है (इस प्रकार मूल्य लौटाया जाता है undefined), लेकिन यह एक टाइमर शुरू करता है, जो 1 वें के बाद 'वूू' वापस करने के लिए एक फ़ंक्शन निष्पादित करता है। लेकिन जैसा कि आप देख सकते हैं, बार को सौंपा गया मान तुरंत foo () से लौटा हुआ सामान है, जो बाद में कुछ और नहीं आता है।

तो, हम इस मुद्दे से कैसे निपट सकते हैं?

आइए एक प्रमोशन के लिए हमारे फ़ंक्शन से पूछें । वादा वास्तव में इसका अर्थ है: इसका मतलब है कि फ़ंक्शन आपको भविष्य में प्राप्त होने वाले किसी आउटपुट के साथ प्रदान करने की गारंटी देता है। तो चलिए इसे ऊपर की छोटी सी समस्या के लिए कार्रवाई में देखते हैं:

function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when execution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});

इस प्रकार, सारांश है - एजेक्स आधारित कॉल इत्यादि जैसे असीमित कार्यों से निपटने के लिए, आप resolveउस मूल्य के वादे का उपयोग कर सकते हैं (जिसे आप वापस करना चाहते हैं)। इस प्रकार, संक्षेप में आप अतुल्यकालिक कार्यों में लौटने की बजाय मूल्य को हल करते हैं।

अद्यतन (async / प्रतीक्षा के साथ वादा)

then/catchवादे के साथ काम करने के अलावा , एक और दृष्टिकोण मौजूद है। विचार एक एसिंक्रोनस फ़ंक्शन को पहचानना है और उसके बाद कोड की अगली पंक्ति में जाने से पहले, वादे को हल करने का इंतजार करना है । यह अभी भी promisesहुड के नीचे है, लेकिन एक अलग वाक्य रचनात्मक दृष्टिकोण के साथ। चीजों को स्पष्ट करने के लिए, आप नीचे एक तुलना पा सकते हैं:

फिर / पकड़ संस्करण:

function fetchUsers(){
   let users = [];
   getUsers()
   .then(_users => users = _users)
   .catch(err =>{
      throw err
   })
   return users;
 }

async / प्रतीक्षा संस्करण:

  async function fetchUsers(){
     try{
        let users = await getUsers()
        return users;
     }
     catch(err){
        throw err;
     }
  }

बेशक सिंक्रोनस अनुरोध, वादे जैसे कई दृष्टिकोण हैं, लेकिन मेरे अनुभव से मुझे लगता है कि आपको कॉलबैक दृष्टिकोण का उपयोग करना चाहिए। जावास्क्रिप्ट के असीमित व्यवहार के लिए यह स्वाभाविक है। तो, आपका कोड स्निपेट थोड़ा अलग फिर से लिख सकता है:

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            myCallback(response);
        }
    });

    return result;
}

function myCallback(response) {
    // Does something.
}

यह उन स्थानों में से एक है जहां कई नए जावास्क्रिप्ट ढांचे में उपयोग किए जाने वाले डेटा बाध्यकारी के दो तरीके आपके लिए बहुत काम करेंगे ...

इसलिए यदि आप कोणीय, प्रतिक्रिया या किसी भी अन्य ढांचे का उपयोग कर रहे हैं जो डेटा बाध्यकारी के दो तरीकों से करते हैं, तो यह समस्या आपके लिए बस तय की जाती है, इसलिए आसान शब्द में, आपका परिणाम undefinedपहले चरण में होता है, इसलिए आपको result = undefinedडेटा प्राप्त करने से पहले मिल गया है , फिर जैसे ही आप परिणाम प्राप्त करेंगे, यह अपडेट हो जाएगा और नए मूल्य को सौंपा जाएगा जो आपके अजाक्स कॉल का जवाब दे रहा है ...

लेकिन जैसा कि आपने इस प्रश्न में पूछा था, उदाहरण के लिए आप शुद्ध जावास्क्रिप्ट या jQuery में इसे कैसे कर सकते हैं ?

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

उदाहरण के लिए , यदि आप jQuery का उपयोग कर रहे हैं , तो आप ऐसा कुछ कर सकते हैं:

$(document).ready(function(){
    function foo() {
        $.ajax({url: "api/data", success: function(data){
            fooDone(data); //after we have data, we pass it to fooDone
        }});
    };

    function fooDone(data) {
        console.log(data); //fooDone has the data and console.log it
    };

    foo(); //call happens here
});

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


यहां दिए गए अधिकांश उत्तर उपयोगी सुझाव देते हैं जब आपके पास एक एकल एसिंक ऑपरेशन होता है, लेकिन कभी-कभी, यह तब आता है जब आपको किसी सरणी या अन्य सूची-जैसी संरचना में प्रत्येक प्रविष्टि के लिए एसिंक्रोनस ऑपरेशन करने की आवश्यकता होती है। प्रलोभन यह करना है:

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

उदाहरण:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

कारण यह नहीं है कि जब doSomethingAsyncतक आप परिणामों का उपयोग करने की कोशिश कर रहे हैं तब तक कॉलबैक तब तक नहीं चलते हैं।

इसलिए, यदि आपके पास कोई सरणी (या किसी प्रकार की सूची है) और प्रत्येक प्रविष्टि के लिए एसिंक ऑपरेशन करना चाहते हैं, तो आपके पास दो विकल्प हैं: समानांतर (ओवरलैपिंग) में ऑपरेशन करें, या श्रृंखला में (अनुक्रम में एक के बाद एक)।

समानांतर

आप उन सभी को शुरू कर सकते हैं और ट्रैक कर सकते हैं कि आप कितने कॉलबैक की उम्मीद कर रहे हैं, और तब परिणामों का उपयोग करें जब आप कई कॉलबैक प्राप्त कर चुके हैं:

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

उदाहरण:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(हम दूर कर सकते हैं expectingऔर बस उपयोग कर सकते हैं results.length === theArray.length, लेकिन यह हमें उस संभावना के लिए खुला छोड़ देता है theArrayजो कॉल बकाया होने पर बदल जाता है ...)

ध्यान दें कि परिणाम को उसी स्थिति में सहेजने के लिए हम किस प्रकार indexसे प्रवेश करते हैं, जैसे परिणाम संबंधित होते हैं, भले ही परिणाम ऑर्डर से बाहर आते हैं (क्योंकि एसिंक कॉल जरूरी क्रम में पूरा नहीं होते हैं)।forEachresults

लेकिन क्या होगा यदि आपको उन परिणामों को किसी फ़ंक्शन से वापस करने की आवश्यकता है ? जैसा कि अन्य उत्तरों ने इंगित किया है, आप नहीं कर सकते; आपको अपना फ़ंक्शन स्वीकार करना होगा और कॉलबैक कॉल करना होगा (या then() वापस करना होगा )। यहां एक कॉलबैक संस्करण है:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

उदाहरण:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

या यहां एक संस्करण Promiseबदले में एक संस्करण है :

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

बेशक, अगर doSomethingAsyncहमें त्रुटियां पारित हुईं, तो हमें त्रुटि rejectमिलने पर वादे को अस्वीकार करने के लिए उपयोग किया जाएगा।)

उदाहरण:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(या वैकल्पिक रूप से, आप एक रैपर बना सकते हैं जिसके लिए doSomethingAsyncएक वादा आता है, और फिर नीचे करें ...)

अगर doSomethingAsyncआपको then() , तो आप इसका उपयोग कर सकते हैं Promise.all:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

उदाहरण:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

ध्यान दें कि Promise.allवादे के सभी के परिणामों की एक सरणी के साथ अपने वादे को हल करता है जब वे सब हल कर रहे हैं आप इसे देने के लिए, या खारिज कर दिया अपने वादे जब पहली वादों आप इसे खारिज कर दिया देना की।

शृंखला

मान लीजिए कि आप ऑपरेशन समानांतर में नहीं चाहते हैं? यदि आप उन्हें एक-दूसरे के बाद चलाने के लिए चाहते हैं, तो आपको अगली शुरू करने से पहले प्रत्येक ऑपरेशन को पूरा करने की प्रतीक्षा करनी होगी। यहां एक फ़ंक्शन का एक उदाहरण दिया गया है जो परिणाम देता है और परिणाम के साथ कॉलबैक कॉल करता है:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(चूंकि हम श्रृंखला में काम कर रहे हैं, हम केवल इसलिए उपयोग कर सकते हैं results.push(result)क्योंकि हम जानते हैं कि हमें ऑर्डर के परिणाम नहीं मिलेंगे। उपरोक्त में हम इस्तेमाल कर सकते थे results[index] = result;, लेकिन निम्नलिखित में से कुछ उदाहरणों में हमारे पास इंडेक्स नहीं है उपयोग करने के लिए।)

उदाहरण:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(या फिर, इसके लिए एक रैपर बनाएं doSomethingAsyncजिससे आपको वादा किया जा सके और नीचे ...)

यदि doSomethingAsyncआप एक वादा देता है, अगर आप (जैसे एक transpiler साथ शायद ES2017 + सिंटैक्स का उपयोग कर सकते हैं कोलाहल ), आप एक का उपयोग कर सकते async/await के साथ for-ofऔर await:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

उदाहरण:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

यदि आप ES2017 + वाक्यविन्यास (अभी तक) का उपयोग नहीं कर सकते हैं, तो आप "वादा कम करें" पैटर्न पर एक भिन्नता का उपयोग कर सकते हैं (यह सामान्य वचन से कम जटिल है क्योंकि हम परिणाम को एक से अगले में पास नहीं कर रहे हैं, बल्कि इसके बजाय अपने परिणामों को एक सरणी में इकट्ठा करना):

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

उदाहरण:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

... जो ES2015 + तीर कार्यों के साथ कम बोझिल है :

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

उदाहरण:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}


सफलता के callback()अंदर एक समारोह का प्रयोग करें foo()। इस तरह से प्रयास करें। यह समझना आसान और आसान है।

var lat = "";
var lon = "";
function callback(data) {
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();

सबसे सरल समाधान एक जावास्क्रिप्ट फ़ंक्शन बना रहा है और इसे अजाक्स successकॉलबैक के लिए कॉल करें ।

function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 





ecmascript-2017