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




15 Answers

यदि आप अपने कोड में 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 API, कोणीय या वादे का उपयोग करने वालों के लिए मैंने नीचे एक और जवाब जोड़ा है )

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

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

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

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

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

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

(Fiddle)

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

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

उपयोग होगा:

getFive(onComplete);

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

संभव समाधान

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

  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 पूर्ण होने पर प्रतिक्रिया कैसे करें।

इसलिए:

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

(fiddle)

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

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

javascript ajax asynchronous ecmascript-6 ecmascript-2017

मेरे पास एक फ़ंक्शन 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`.



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

इसका मतलब है 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
}

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




सबसे सरल समाधान एक जावास्क्रिप्ट फ़ंक्शन बना रहा है और इसे अजाक्स 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);    
}); 



Angular1

AngularJS का उपयोग कर रहे लोगों के लिए , इस स्थिति का उपयोग कर संभाल सकते हैं Promises

Here यह कहता है,

वादा का उपयोग अतुल्यकालिक कार्यों को अनचाहे करने के लिए किया जा सकता है और एक को कई कार्यों को एक साथ करने की अनुमति देता है।

आप here एक अच्छी व्याख्या भी पा सकते हैं ।

नीचे उल्लिखित docs में पाया गया उदाहरण ।

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

कोणीय 2 और बाद में

में Angular2निम्नलिखित उदाहरण को देखो, लेकिन साथ अपने recommended का उपयोग करने के Observablesसाथ Angular2

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

आप इस तरह से उपभोग कर सकते हैं,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

यहां original पोस्ट देखें । लेकिन टाइपस्क्रिप्ट मूल es6 वादा का समर्थन नहीं करता है , अगर आप इसका उपयोग करना चाहते हैं, तो आपको इसके लिए प्लगइन की आवश्यकता हो सकती है।

इसके अतिरिक्त यहां वादे का spec परिभाषित किया गया है।




इस उदाहरण पर एक नज़र डालें:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

जैसा कि आप देख सकते हैं एक हल किए गए वादेgetJoke को वापस कर रहा है (यह लौटने पर हल हो जाता है )। तो आप $ http.get अनुरोध पूरा होने तक प्रतीक्षा करें और फिर console.log (res.joke) निष्पादित किया जाता है (एक सामान्य असीमित प्रवाह के रूप में)।res.data.value

यह plnkr है:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/




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

इसलिए यदि आप कोणीय, प्रतिक्रिया या किसी भी अन्य ढांचे का उपयोग कर रहे हैं जो डेटा बाध्यकारी के दो तरीकों से करते हैं, तो यह समस्या आपके लिए बस तय की जाती है, इसलिए आसान शब्द में, आपका परिणाम 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
});

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




संक्षिप्त उत्तर यह है कि आपको इस तरह एक कॉलबैक लागू करना होगा:

function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});



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

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

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

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

(async function(){

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

})()

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




एक और समाधान अनुक्रमिक निष्पादक nsynjs के माध्यम से कोड निष्पादित nsynjs

अगर अंतर्निहित कार्य को बढ़ावा दिया जाता है

nsynjs अनुक्रमिक रूप से सभी वादों का मूल्यांकन करेंगे, और dataसंपत्ति में वादा परिणाम डाल देंगे :

function synchronousCode() {

    var getURL = function(url) {
        return window.fetch(url).data.text().data;
    };
    
    var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
    console.log('received bytes:',getURL(url).length);
    
};

nsynjs.run(synchronousCode,{},function(){
    console.log('synchronousCode done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

अगर अंतर्निहित कार्य को प्रमाणित नहीं किया जाता है

चरण 1. nsynjs- जागरूक रैपर में कॉलबैक के साथ फ़ंक्शन लपेटें (यदि यह प्रोमोसिफाइड संस्करण है, तो आप इस परीक्षण को छोड़ सकते हैं):

var ajaxGet = function (ctx,url) {
    var res = {};
    var ex;
    $.ajax(url)
    .done(function (data) {
        res.data = data;
    })
    .fail(function(e) {
        ex = e;
    })
    .always(function() {
        ctx.resume(ex);
    });
    return res;
};
ajaxGet.nsynjsHasCallback = true;

चरण 2. सिंक्रोनस तर्क को फ़ंक्शन में रखें:

function process() {
    console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}

चरण 3. nnsynjs के माध्यम से तुल्यकालिक तरीके से कार्य चलाएं:

nsynjs.run(process,this,function () {
    console.log("synchronous function finished");
});

Nsynjs सभी ऑपरेटरों और अभिव्यक्तियों का मूल्यांकन चरण-दर-चरण का मूल्यांकन करेगा, अगर कुछ धीमे फ़ंक्शन का परिणाम तैयार नहीं होता है तो निष्पादन रोकना।

यहां अधिक उदाहरण: https://github.com/amaksr/nsynjs/tree/master/examples




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

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

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



ईसीएमएस्क्रिप्ट 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);



संक्षिप्त उत्तर : आपकी 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




सवाल यह था:

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

जिसका अर्थ इस प्रकार किया जा सकता है:

कैसे बनाने के लिए अतुल्यकालिक कोड नज़र तुल्यकालिक ?

समाधान कॉलबैक से बचने के लिए होगा, और वादे और async / प्रतीक्षा के संयोजन का उपयोग करें ।

मैं अजाक्स अनुरोध के लिए एक उदाहरण देना चाहता हूं।

(हालांकि इसे जावास्क्रिप्ट में लिखा जा सकता है, मैं इसे पायथन में लिखना पसंद करता हूं, और इसे Transcrypt का उपयोग करके जावास्क्रिप्ट में संकलित करना पसंद करता Transcrypt । यह पर्याप्त स्पष्ट होगा।)

पहले JQuery उपयोग सक्षम करने देता है, के लिए $के रूप में उपलब्ध S:

__pragma__ ('alias', 'S', '$')

एक ऐसा कार्य परिभाषित करें जो वादा करता है , इस मामले में एक अजाक्स कॉल:

def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()

एसिंक्रोनस कोड का उपयोग करें जैसे कि यह सिंक्रोनस था :

async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")



ES2017 का उपयोग करके आपको इसे फ़ंक्शन घोषणा के रूप में रखना चाहिए

async function foo() {
    var response = await $.ajax({url: '...'})
    return response;
}

और इसे इस तरह निष्पादित कर रहा है।

(async function() {
    try {
        var result = await foo()
        console.log(result)
    } catch (e) {}
})()

या वादा वाक्यविन्यास

foo().then(response => {
    console.log(response)

}).catch(error => {
    console.log(error)

})



आप पर कोड फेंकने की बजाय, 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()

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




Related