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


मेरे पास एक समारोह है 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`.

4321
2018-01-08 17:06


मूल


@MaximShoustin मैंने एक जावास्क्रिप्ट केवल उत्तर (कोई jQuery नहीं) जोड़ा है, लेकिन फ़ेलिक्स ने कहा - "मैं AJAX कॉल से प्रतिक्रिया कैसे वापस कर सकता हूं" वास्तव में यह कहने का एक अच्छा तरीका है "जावास्क्रिप्ट में समरूपता कैसे काम करती है"। कोणीय का जिक्र नहीं है $http jQuery के बहुत समान है $.ajax वैसे भी कुछ मामूली अंतर (जैसे पाचन चक्र के साथ इंटरऑपिंग) के साथ। - Benjamin Gruenbaum
ऐसा न करें उपयोग async: false। यह ब्राउज़र को फ्रीज करेगा और उपयोगकर्ताओं को दूर चला जाएगा। पढ़ना blog.slaks.net/2015-01-04/async-method-patterns एसिंक्रोनस ऑपरेशंस के साथ काम करने के तरीके सीखने के लिए। - SLaks
यह संभव है जैसे आपने एसिंक को विज्ञापन करके ऐसा किया: पहले पैरामीटर की विशेषता के रूप में गलत। नीचे मेरा जवाब देखें। @tvanfosson ने स्टैक ओवरफ्लो पर यह समाधान दिया। - arrowman
यह मैं तुम्हारी मदद करता हूँ codingbin.com/get-return-data-ajax-call - Manoj Kumar
@SLaks किसी को कृपया एयरएशिया.com पर वेबसाइट "रॉक स्टार डेवलपर्स" पर रिले करें। यह एक महान लाइव केस स्टडी है (अजाक्स कॉल द्वारा कुछ सेकेंड लेते हुए बढ़ाया गया है) क्यों कभी एसिंक का उपयोग नहीं करना: झूठा। - Mâtt Frëëman


जवाब:


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

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

समस्या

 में अजाक्स के लिए खड़ा है अतुल्यकालिक । इसका मतलब है कि अनुरोध भेजना (या प्रतिक्रिया प्राप्त करना) सामान्य निष्पादन प्रवाह से बाहर निकाला जाता है। आपके उदाहरण में, $.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(); करना है रुकिए जब तक फ़ंक्शन परिणाम नहीं देता है।

अतुल्यकालिक

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

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

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

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


समाधान की)

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

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

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

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

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

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

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


ES2017 +: के साथ वादा करता है async/await

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

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

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

आप इसके बारे में अधिक पढ़ सकते हैं async तथा 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 a second (just for the sake of this example)
    await delay(1000);
    // 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);
  });

नई ब्राउज़र तथा नोड संस्करण का समर्थन करते हैं async/await। आप मदद के साथ अपने कोड को ईएस 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 हम जिस फ़ंक्शन को पास करते हैं उसका संदर्भ लेंगे foo जब हम इसे कॉल करते हैं और हम इसे आसानी से पास करते हैं success। अर्थात। एक बार अजाक्स अनुरोध सफल होने के बाद, $.ajax कॉल करेंगे callback और कॉलबैक को प्रतिक्रिया पास करें (जिसे संदर्भित किया जा सकता है result, चूंकि हमने कॉलबैक को परिभाषित किया है)।

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

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

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


ES2015 +: के साथ वादा करता हूँ फिर()

वादा एपीआई ईसीएमएस्क्रिप्ट 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 के वादे के कस्टम कार्यान्वयन हैं (वादा एपीआई मानकीकृत करने से पहले)। वे लगभग वादे की तरह व्यवहार करते हैं लेकिन थोड़ा अलग एपीआई का पर्दाफाश करते हैं।

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;
}

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

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


4666
2018-01-08 17:06



@Pommy: यदि आप jQuery का उपयोग करना चाहते हैं, तो आपको इसे शामिल करना होगा। कृपया देखें docs.jquery.com/Tutorials:Getting_Started_with_jQuery। - Felix Kling
समाधान 1 में, उप jQuery, मैं इस पंक्ति को समझ नहीं सका: If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax. (हाँ, मुझे एहसास है कि इस मामले में मेरी निक एक विडंबनापूर्ण है) - gibberish
@ गिबरिश: मम्म, मुझे नहीं पता कि इसे कैसे स्पष्ट किया जा सकता है। क्या आप देखते हैं कि कैसे foo कहा जाता है और इसे एक समारोह पारित किया जाता है (foo(function(result) {....});)? result इस समारोह के अंदर प्रयोग किया जाता है और अजाक्स अनुरोध की प्रतिक्रिया है। इस फ़ंक्शन को देखने के लिए, foo का पहला पैरामीटर कहा जाता है callback और सौंपा गया success एक अज्ञात समारोह के बजाय। इसलिए, $.ajax कॉल करेंगे callback जब अनुरोध सफल हुआ। मैंने इसे थोड़ा और समझाने की कोशिश की। - Felix Kling
इस प्रश्न के लिए चैट मृत है इसलिए मुझे यकीन नहीं है कि उल्लिखित परिवर्तनों का प्रस्ताव कहां से किया जाए, लेकिन मैं प्रस्ताव करता हूं: 1) सिंक्रोनस भाग को एक साधारण चर्चा में बदलें कि यह कैसे करना है इसके कोड कोड के साथ बुरा क्यों है। 2) कॉलबैक उदाहरणों को निकालें / विलय करें ताकि केवल अधिक लचीला डिफर्ड दृष्टिकोण दिखाया जा सके, जो मुझे लगता है कि जावास्क्रिप्ट सीखने वालों के लिए भी थोड़ा आसान हो सकता है। - Chris Moschini
@ जेसी: मुझे लगता है कि आपने जवाब के उस हिस्से को गलत समझा। आप उपयोग नहीं कर सकते $.getJSON अगर आप अजाक्स अनुरोध को तुल्यकालिक होना चाहते हैं। हालांकि, आपको घटना को सिंक्रोनस होने का अनुरोध नहीं करना चाहिए, इसलिए यह लागू नहीं होता है। आपको प्रतिक्रियाओं को संभालने के लिए कॉलबैक या वादे का उपयोग करना चाहिए, क्योंकि इसे उत्तर में पहले समझाया गया है। - Felix Kling


अगर तुम हो नहीं अपने कोड में jQuery का उपयोग करके, यह जवाब आपके लिए है

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

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

फ़ेलिक्स क्लिंग ने AJAX के लिए jQuery का उपयोग करने वाले लोगों के लिए एक उत्तर लिखने का एक अच्छा काम किया है, मैंने उन लोगों के लिए एक विकल्प प्रदान करने का निर्णय लिया है जो नहीं हैं।

(नोट, नए का उपयोग करने वालों के लिए fetch एपीआई, कोणीय या वादे मैंने नीचे एक और जवाब जोड़ा है)


आप क्या सामना कर रहे हैं

यह अन्य उत्तर से "समस्या का स्पष्टीकरण" का संक्षिप्त सारांश है, यदि आप इसे पढ़ने के बाद सुनिश्चित नहीं हैं, तो इसे पढ़ें।

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

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

यहां एक सरल सादृश्य है

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(फिडल)

का मूल्य a वापस आ गया है undefined के बाद से a=5 भाग अभी तक निष्पादित नहीं किया गया है। AJAX इस तरह कार्य करता है, सर्वर को आपके ब्राउज़र को यह बताने का मौका मिलने से पहले आप मूल्य वापस कर रहे हैं कि वह मान क्या है।

इस समस्या का एक संभावित समाधान कोड है फिर से सक्रिय रूप से , गणना पूरी होने पर अपने कार्यक्रम को क्या करना है।

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

यह कहा जाता है सीपीएस। असल में, हम गुजर रहे हैं getFive जब यह पूरा हो जाता है तो प्रदर्शन करने के लिए एक क्रिया, हम एक घटना पूर्ण होने पर हमारे कोड को कैसे प्रतिक्रिया दे रहे हैं (जैसे हमारे AJAX कॉल, या इस मामले में टाइमआउट)।

उपयोग होगा:

getFive(onComplete);

स्क्रीन पर "5" को सतर्क करना चाहिए। (फिडल)

संभव समाधान

मूल रूप से इसे हल करने के दो तरीके हैं:

  1. AJAX कॉल सिंक्रोनस बनाएं (इसे SJAX कहते हैं)।
  2. कॉलबैक के साथ ठीक से काम करने के लिए अपने कोड को पुन: व्यवस्थित करें।

1. तुल्यकालिक AJAX - ऐसा मत करो !!

सिंक्रोनस AJAX के लिए के रूप में, ऐसा मत करो! फेलिक्स का जवाब कुछ आकर्षक तर्क उठाता है कि यह एक बुरा विचार क्यों है। इसे समेकित करने के लिए, यह उपयोगकर्ता के ब्राउज़र को तब तक स्थिर कर देगा जब तक सर्वर प्रतिक्रिया न दे और बहुत खराब उपयोगकर्ता अनुभव न करे। यहां एमडीएन से लिया गया एक और संक्षिप्त सारांश क्यों है:

XMLHttpRequest सिंक्रोनस और असिंक्रोनस संचार दोनों का समर्थन करता है। सामान्य रूप से, हालांकि, प्रदर्शन कारणों से सिंक्रोनस अनुरोधों के लिए एसिंक्रोनस अनुरोधों को प्राथमिकता दी जानी चाहिए।

संक्षेप में, तुल्यकालिक अनुरोध कोड के निष्पादन को अवरुद्ध करते हैं ... ... इससे गंभीर समस्याएं हो सकती हैं ...

अगर तुम है ऐसा करने के लिए, आप एक ध्वज पास कर सकते हैं: यहां कैसे:

var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. कोड पुनर्गठन

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

इसलिए:

var result = foo();
// code that depends on `result` goes here

हो जाता है:

foo(function(result) {
    // code that depends on `result`
});

यहां हमने एक अज्ञात फ़ंक्शन पारित किया है, लेकिन हम किसी मौजूदा फ़ंक्शन के संदर्भ को आसानी से पास कर सकते हैं, जिससे यह दिखता है:

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

इस प्रकार के कॉलबैक डिज़ाइन को कैसे किया जाता है, इस बारे में अधिक जानकारी के लिए, फ़ेलिक्स के उत्तर की जांच करें।

अब, चलो अपने आप को तदनुसार कार्य करने के लिए परिभाषित करते हैं

function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(बेला)

हमने अब हमारे फू फ़ंक्शन को चलाने के लिए एक क्रिया को स्वीकार कर लिया है जब AJAX सफलतापूर्वक पूर्ण हो जाता है, हम यह जांच कर आगे बढ़ा सकते हैं कि प्रतिक्रिया स्थिति 200 नहीं है और तदनुसार कार्य कर रही है (एक असफल हैंडलर बनाएं और ऐसे)। प्रभावी रूप से हमारे मुद्दे को हल करना।

यदि आपको अभी भी इसे समझने में कठिनाई हो रही है एजेक्स शुरू करने गाइड शुरू करें एमडीएन में


888
2018-05-29 23:30



"तुल्यकालिक अनुरोध कोड के निष्पादन को अवरुद्ध करते हैं और स्मृति और घटनाओं को रिसाव कर सकते हैं" एक तुल्यकालिक अनुरोध कैसे स्मृति को रिसाव कर सकता है? - Matthew G
@ मैथ्यूजी मैंने इसमें एक बक्षीस जोड़ा है यह प्रश्न, मैं देखूंगा कि मैं क्या कर सकता हूं। मैं उत्तर समय में उद्धरण को उद्धृत कर रहा हूं। - Benjamin Gruenbaum
बस संदर्भ के लिए, एक्सएचआर 2 हमें उपयोग करने की अनुमति देता है onload हैंडलर, जो केवल जब आग लगती है readyState है 4। बेशक, यह आईई 8 में समर्थित नहीं है। (iirc, पुष्टि की आवश्यकता हो सकती है।) - Florian Margaine
कॉलबैक के रूप में अज्ञात फ़ंक्शन को पास करने का तरीका स्पष्ट है लेकिन भ्रामक है। उदाहरण var bar = foo (); परिभाषित करने के लिए एक चर के लिए पूछ रहा है, जबकि आपके सुझाए गए foo (functim () {}); बार परिभाषित नहीं करता है - Robbie Averill
@ बेंजामिन ग्रुएनबाम मैं सामग्री कैसे वापस कर सकता हूं result एक चर में जो मैं अपने कोड में एचटीएमएल के साथ प्रिंट करने के बजाय कहीं और उपयोग कर सकता हूं? - MorganFR


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() के अंतर्गत this.statusText जैसा 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 पाश के साथ ... लेकिन गंभीरता से?)

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

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


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

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

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

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