मैं एसिंक्रोनस कॉल से प्रतिक्रिया कैसे लौटाऊं?
मेरे पास एक फ़ंक्शन है foo
जो एक अतुल्यकालिक अनुरोध करता है। मैं प्रतिक्रिया / परिणाम कैसे वापस कर सकता हूं foo
?
मैंने कॉलबैक से मान लौटाने की कोशिश की, साथ ही फ़ंक्शन के अंदर एक स्थानीय चर के परिणाम को असाइन करने और उस एक को वापस करने के लिए, लेकिन उन तरीकों में से कोई भी वास्तव में प्रतिक्रिया नहीं लौटाता है (वे सभी वापसी करते हैं undefined
या जो भी चर result
का प्रारंभिक मूल्य है) ।
JQuery के ajax
फ़ंक्शन का उपयोग करके उदाहरण :
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result; // It always returns `undefined`
}
नोड.जेएस का उपयोग करके उदाहरण:
function foo() {
var result;
fs.readFile("path/to/file", function(err, data) {
result = data;
// return data; // <- I tried that one as well
});
return result; // It always returns `undefined`
}
then
एक वादा के ब्लॉक का उपयोग कर उदाहरण :
function foo() {
var result;
fetch(url).then(function(response) {
result = response;
// return response; // <- I tried that one as well
});
return result; // It always returns `undefined`
}
जवाब
→ विभिन्न उदाहरणों के साथ async व्यवहार की अधिक सामान्य व्याख्या के लिए, कृपया देखें कि किसी फ़ंक्शन के अंदर इसे संशोधित करने के बाद मेरा वैरिएबल अनलक्ड क्यों है? - एसिंक्रोनस कोड संदर्भ
→ यदि आप पहले से ही समस्या को समझते हैं, तो नीचे दिए गए संभावित समाधानों पर जाएं।
समस्या
एक में अजाक्स के लिए खड़ा है अतुल्यकालिक । इसका मतलब है कि अनुरोध भेजना (या प्रतिक्रिया प्राप्त करना) सामान्य निष्पादन प्रवाह से बाहर ले जाया जाता है। आपके उदाहरण में, $.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 the item
});
doSomethingElse();
प्रतिक्रिया की प्रतीक्षा करने के बजाय, निष्पादन तुरंत जारी रहता है और अजाक्स कॉल के निष्पादित होने के बाद बयान जारी होता है। प्रतिक्रिया अंततः प्राप्त करने के लिए, आप एक कॉलबैक प्रदान करते हैं जिसे एक बार प्रतिक्रिया प्राप्त होने के बाद कॉल किया जाता है, एक कॉलबैक (कुछ वापस कॉल करें ?)। कॉलबैक कहे जाने से पहले उस कॉल के बाद आने वाले किसी भी स्टेटमेंट को निष्पादित किया जाता है।
समाधान)
जावास्क्रिप्ट की अतुल्यकालिक प्रकृति को गले लगाओ! हालांकि कुछ अतुल्यकालिक संचालन तुल्यकालिक समकक्ष प्रदान करते हैं (इसलिए "अजाक्स"), यह आमतौर पर उन्हें उपयोग करने के लिए हतोत्साहित किया जाता है, खासकर एक ब्राउज़र संदर्भ में।
यह क्यों बुरा है आप पूछें?
जावास्क्रिप्ट ब्राउज़र के यूआई थ्रेड में चलता है और कोई भी लंबे समय तक चलने वाली प्रक्रिया यूआई को लॉक कर देगी, जिससे यह अनुत्तरदायी हो जाएगा। इसके अतिरिक्त, जावास्क्रिप्ट के लिए निष्पादन समय पर एक ऊपरी सीमा है और ब्राउज़र उपयोगकर्ता से पूछेगा कि निष्पादन जारी रखना है या नहीं।
यह सब एक बहुत बुरा उपयोगकर्ता अनुभव है। उपयोगकर्ता यह बताने में सक्षम नहीं होगा कि सब कुछ ठीक काम कर रहा है या नहीं। इसके अलावा, प्रभाव धीमे कनेक्शन वाले उपयोगकर्ताओं के लिए और भी बुरा होगा।
निम्नलिखित में हम तीन अलग-अलग समाधानों को देखेंगे जो सभी एक-दूसरे के शीर्ष पर बन रहे हैं:
async/await
यदि आप ट्रांसपिलर या रीजनरेटर का उपयोग करते हैं तो पुराने ब्राउज़रों में उपलब्ध (ES2017 +) के साथ वादा करता है- कॉलबैक (नोड में लोकप्रिय)
then()
यदि आप कई वादे पुस्तकालयों में से एक का उपयोग करते हैं, तो पुराने ब्राउज़रों में उपलब्ध (ES2015 +) के साथ वादे
सभी तीन वर्तमान ब्राउज़रों में उपलब्ध हैं, और नोड 7+।
ES2017 +: के साथ वादा करता है async/await
2017 में जारी ECMAScript संस्करण ने अतुल्यकालिक कार्यों के लिए सिंटैक्स-स्तरीय समर्थन पेश किया । की मदद से async
और await
, आप एसिंक्रोनस को "सिंक्रोनस स्टाइल" में लिख सकते हैं। कोड अभी भी अतुल्यकालिक है, लेकिन इसे पढ़ना / समझना आसान है।
async/await
वादों के शीर्ष पर बनाता है: एक async
फ़ंक्शन हमेशा एक वादा वापस करता है। await
वादे को "उजागर" करता है और यदि वादे को अस्वीकार कर दिया जाता है तो या तो मूल्य को हल किया जाता है या एक त्रुटि को दूर किया जाता है।
महत्वपूर्ण: आप केवल await
एक async
फ़ंक्शन के अंदर उपयोग कर सकते हैं । अभी, शीर्ष-स्तर await
अभी तक समर्थित नहीं है, इसलिए आपको एक संदर्भ शुरू करने के लिए एक async IIFE ( तत्काल इनवॉइस फंक्शन एक्सप्रेशन ) करना पड़ सकता है async
।
आप MDN के बारे में 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 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;
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let books = await getAllBooks();
console.log(books);
})();
वर्तमान ब्राउज़र और नोड संस्करण समर्थन करते हैं async/await
। आप पुनर्जन्मकर्ता (या ऐसे उपकरण जो पुनर्योजी का उपयोग करते हैं, जैसे बेबल ) की सहायता से अपने कोड को ES5 में बदलकर पुराने वातावरण का समर्थन कर सकते हैं ।
कार्य कॉलबैक स्वीकार करते हैं
कॉलबैक तब होता है जब फ़ंक्शन 1 फ़ंक्शन को पास किया जाता है। फ़ंक्शन 2 जब भी तैयार होता है तो फ़ंक्शन 1 कॉल कर सकता है। एक अतुल्यकालिक प्रक्रिया के संदर्भ में, जब भी अतुल्यकालिक प्रक्रिया की जाती है तो कॉलबैक कहा जाएगा। आमतौर पर, परिणाम कॉलबैक को पास किया जाता है।
प्रश्न के उदाहरण में, आप 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);
}
});
}
कॉलबैक का उपयोग करके कोड लिखना आसान हो सकता है जितना कि यह लग सकता है। आखिरकार, ब्राउज़र में जावास्क्रिप्ट भारी घटना-संचालित (DOM इवेंट) है। अजाक्स प्रतिक्रिया प्राप्त करना एक घटना के अलावा और कुछ नहीं है।
जब आपको थर्ड-पार्टी कोड के साथ काम करना पड़ता है, तो कठिनाइयाँ आ सकती हैं, लेकिन ज्यादातर समस्याओं को केवल एप्लिकेशन प्रवाह के माध्यम से सोचकर हल किया जा सकता है।
ES2015 +: तब के साथ वादा ()
वादा एपीआई ECMAScript 6 (ES2015) की एक नई सुविधा है, लेकिन यह अच्छा है ब्राउज़र समर्थन पहले से ही। कई पुस्तकालय भी हैं जो मानक वादे एपीआई को लागू करते हैं और अतुल्यकालिक कार्यों (जैसे ब्लूबर्ड ) के उपयोग और संरचना को आसान बनाने के लिए अतिरिक्त तरीके प्रदान करते हैं ।
वादे भविष्य के मूल्यों के लिए कंटेनर हैं। जब वादा मूल्य प्राप्त करता है (यह हल हो जाता है ) या जब इसे रद्द ( अस्वीकार ) किया जाता है, तो यह उसके सभी "श्रोताओं" को सूचित करता है जो इस मूल्य तक पहुंचना चाहते हैं।
सादे कॉलबैक से अधिक लाभ यह है कि वे आपको अपना कोड हटाने की अनुमति देते हैं और वे रचना करना आसान होते हैं।
यहाँ एक वादा का उपयोग करने का एक उदाहरण है:
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
});
उन सभी फायदों के बारे में बताते हुए जो वादा करते हैं, इस उत्तर के दायरे से परे हैं, लेकिन यदि आप नया कोड लिखते हैं, तो आपको उन पर गंभीरता से विचार करना चाहिए। वे आपके कोड की एक महान अमूर्तता और अलगाव प्रदान करते हैं।
वादों के बारे में अधिक जानकारी: HTML5 चट्टानें - जावास्क्रिप्ट वादे
साइड नोट: 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 Ajax आस्थगित वस्तु देता है, न कि सर्वर से प्रतिक्रिया। इसका मतलब है कि 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
कॉलबैक का उपयोग कर सकते हैं या jqXHR ऑब्जेक्ट की responseText
संपत्ति तक पहुंच सकते हैं :
function foo() {
var jqXHR = $.ajax({
//...
async: false
});
return jqXHR.responseText;
}
आप किसी भी अन्य jQuery अजाक्स विधि, के रूप में इस तरह के प्रयोग करते हैं $.get
, $.getJSON
आदि, आप के लिए इसे बदलने के लिए है $.ajax
(चूंकि आप केवल करने के लिए कॉन्फ़िगरेशन पैरामीटर पारित कर सकते हैं $.ajax
)।
सचेत! समकालिक JSONP अनुरोध करना संभव नहीं है । अपने बहुत ही स्वभाव से JSONP हमेशा अतुल्यकालिक है (इस विकल्प पर विचार नहीं करने का एक और कारण)।
यदि आप अपने कोड में 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'
एजेक्स के लिए 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);
}
इसे CPS कहा जाता है । मूल रूप से, getFive
जब हम इसे पूरा करते हैं तो प्रदर्शन करने के लिए एक कार्रवाई कर रहे हैं, हम अपना कोड बता रहे हैं कि जब कोई घटना (जैसे हमारे AJAX कॉल, या इस मामले में समय समाप्त) पर प्रतिक्रिया कैसे करें।
उपयोग होगा:
getFive(onComplete);
जिसे स्क्रीन पर "5" को अलर्ट करना चाहिए। (फिडेल) ।
संभव समाधान
मूल रूप से इसे हल करने के दो तरीके हैं:
- AJAX कॉल को तुल्यकालिक बनाएं (इसे SJAX कहते हैं)।
- कॉलबैक के साथ ठीक से काम करने के लिए अपने कोड को पुनर्स्थापित करें।
1. तुल्यकालिक AJAX - यह मत करो !!
तुल्यकालिक AJAX के लिए, यह मत करो! फेलिक्स का जवाब इस बारे में कुछ मजबूर तर्क देता है कि यह एक बुरा विचार क्यों है। इसे सारांशित करने के लिए, यह उपयोगकर्ता के ब्राउज़र को तब तक फ्रीज करेगा, जब तक कि सर्वर प्रतिक्रिया नहीं देता है और एक बहुत ही खराब उपयोगकर्ता अनुभव बनाता है। यहाँ MDN से लिया गया एक और संक्षिप्त सारांश क्यों दिया गया है:
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);
इस प्रकार की कॉलबैक डिज़ाइन कैसे की जाती है, इस बारे में अधिक जानकारी के लिए, फेलिक्स के उत्तर की जाँच करें।
अब, हम foo को उसी के अनुसार कार्य करने के लिए परिभाषित करते हैं
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 नहीं है और तदनुसार कार्य कर रहा है (एक असफल हैंडलर और ऐसे बनाएं)। हमारे मुद्दे को प्रभावी ढंग से हल करना।
यदि आपको अभी भी यह समझने में कठिन समय हो रहा है कि इस AJAX को एमडीएन में शुरू करने के लिए गाइड पढ़ें ।
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()
}
जैसा कि आप देख सकते हैं:
- यह सूचीबद्ध अन्य सभी कार्यों से छोटा है।
- कॉलबैक को सीधे सेट किया जाता है (ताकि कोई अतिरिक्त अनावश्यक बंद न हो)।
- यह नया ऑनलोड का उपयोग करता है (ताकि आपको रीडिस्टेट और& स्थिति के लिए जांच न करनी पड़े)
- कुछ अन्य स्थितियां हैं जो मुझे याद नहीं हैं कि XMLHttpRequest 1 को कष्टप्रद बनाते हैं।
इस अजाक्स कॉल की प्रतिक्रिया प्राप्त करने के दो तरीके हैं (तीन XMLHttpRequest var name का उपयोग करके):
सबसे साधारण:
this.response
या अगर किसी कारण से आप bind()
किसी वर्ग के लिए कॉलबैक करते हैं:
e.target.response
उदाहरण:
function callback(e){
console.log(this.response);
}
ajax('URL', callback);
या (ऊपर वाला बेहतर अनाम कार्य हमेशा एक समस्या है):
ajax('URL', function(e){console.log(this.response)});
कुछ भी आसान नहीं है।
अब कुछ लोग शायद कहेंगे कि onreadystatechange या यहाँ तक कि XMLHttpRequest वैरिएबल नाम का उपयोग करना बेहतर है। यह गलत है।
XMLHttpRequest उन्नत सुविधाओं की जाँच करें
इसने सभी * आधुनिक ब्राउज़रों का समर्थन किया। और मैं पुष्टि कर सकता हूं क्योंकि मैं XMLHttpRequest 2 के मौजूद होने के बाद से इस दृष्टिकोण का उपयोग कर रहा हूं। मेरे द्वारा उपयोग किए जाने वाले सभी ब्राउज़रों पर मुझे कभी किसी प्रकार की समस्या नहीं हुई।
यदि आप राज्य 2 पर हेडर प्राप्त करना चाहते हैं तो onreadystatechange केवल उपयोगी है।
XMLHttpRequest
वैरिएबल नाम का उपयोग करना एक और बड़ी त्रुटि है क्योंकि आपको ऑनलोड / ओरिडिस्टेटचेंज क्लोजर के अंदर कॉलबैक को निष्पादित करने की आवश्यकता है जो आपने इसे खो दिया है।
अब यदि आप पोस्ट और फॉर्मडाटा का उपयोग करके कुछ और जटिल चाहते हैं तो आप इस फ़ंक्शन को आसानी से बढ़ा सकते हैं:
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);
उपरोक्त स्क्रिप्ट में, आपके पास एक त्रुटि हैंडलर है जो कि सांख्यिकीय रूप से परिभाषित है इसलिए यह फ़ंक्शन से समझौता नहीं करता है। त्रुटि हैंडलर का उपयोग अन्य कार्यों के लिए भी किया जा सकता है।
लेकिन वास्तव में एक त्रुटि को बाहर निकालने का एकमात्र तरीका एक गलत URL लिखना है जिस स्थिति में प्रत्येक ब्राउज़र एक त्रुटि फेंकता है।
त्रुटि हैंडलर शायद उपयोगी होते हैं यदि आप कस्टम हेडर सेट करते हैं, तो प्रतिक्रिया सरणी को ब्लॉब सरणी बफर या जो भी सेट करें ...
यहां तक कि अगर आप 'POSTAPAPAP' विधि को पास करते हैं, तो यह एक त्रुटि नहीं होगी।
यहां तक कि अगर आप फॉर्मडैट के रूप में 'fdggdgilfdghfldj' पास करते हैं तो यह एक त्रुटि नहीं होगी।
पहले मामले में त्रुटि displayAjax()
अंडर this.statusText
में है Method not Allowed
।
दूसरे मामले में, यह बस काम करता है। यदि आपने सही पोस्ट डेटा पास किया है तो आपको सर्वर की तरफ देखना होगा।
क्रॉस-डोमेन ने स्वचालित रूप से थ्रो त्रुटि की अनुमति नहीं दी है।
त्रुटि प्रतिक्रिया में, कोई त्रुटि कोड नहीं हैं।
केवल वही है this.type
जो त्रुटि पर सेट है।
यदि आप पूरी तरह से त्रुटियों पर नियंत्रण नहीं रखते हैं, तो एक त्रुटि हैंडलर क्यों जोड़ें? कॉलबैक फ़ंक्शन में इसके अंदर अधिकांश त्रुटियां दी गई हैं displayAjax()
।
इसलिए: यदि आप URL को ठीक से कॉपी और पेस्ट करने में सक्षम हैं तो त्रुटि जांच की कोई आवश्यकता नहीं है। ;)
पुनश्च: पहले परीक्षण के रूप में मैंने x ('x', displayAjax) लिखा था ... और इसे पूरी तरह से प्रतिक्रिया मिली ... ??? इसलिए मैंने उस फ़ोल्डर की जांच की जहां HTML स्थित है, और 'x.xml' नामक एक फ़ाइल थी। तो भले ही आप अपनी फाइल का एक्सटेंशन XMLHttpRequest 2 WILL FIND IT भूल जाएं । I LOL'd
एक फ़ाइल सिंक्रोनस पढ़ें
ऐसा मत करो।
यदि आप ब्राउज़र को थोड़ी देर के लिए ब्लॉक करना चाहते हैं तो एक अच्छी बड़ी .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');
गैर-अतुल्यकालिक तरीके से ऐसा करने का कोई अन्य तरीका नहीं है। (हाँ, सेटटाइमआउट लूप के साथ ... लेकिन गंभीरता से?)
एक अन्य बिंदु यह है ... यदि आप एपीआई या अपनी खुद की सूची की फाइलों या जो भी आप हमेशा प्रत्येक अनुरोध के लिए अलग-अलग कार्यों का उपयोग करते हैं, के साथ काम करते हैं ...
केवल अगर आपके पास एक पृष्ठ है जहाँ आप हमेशा एक ही XML / JSON लोड करते हैं या आपको केवल एक फ़ंक्शन की आवश्यकता होती है। उस स्थिति में, अजाक्स फ़ंक्शन को थोड़ा संशोधित करें और अपने विशेष फ़ंक्शन के साथ बी को बदलें।
उपरोक्त कार्य बुनियादी उपयोग के लिए हैं।
यदि आप फ़ंक्शन का विस्तार करना चाहते हैं ...
हाँ तुम कर सकते हो।
मैं बहुत सारे API का उपयोग कर रहा हूं और प्रत्येक HTML पेज में जो पहला फ़ंक्शन मैं एकीकृत करता हूं, वह इस उत्तर में पहला अजाक्स फ़ंक्शन है, केवल टीईटी के साथ ...
लेकिन आप XMLHttpRequest 2 के साथ बहुत कुछ कर सकते हैं:
मैंने एक डाउनलोड प्रबंधक बनाया (फिर से शुरू, फ़िलेडर, फाइल सिस्टम के साथ दोनों पक्षों पर श्रेणियों का उपयोग करते हुए), कैनवास का उपयोग करते हुए विभिन्न छवि पुनर्जीवन कन्वर्टर्स, बेस 64images के साथ वेब SQL डेटाबेस को पॉप्युलेट करते हैं और बहुत कुछ ... लेकिन इन मामलों में आपको केवल एक फ़ंक्शन बनाना चाहिए उद्देश्य ... कभी-कभी आपको एक बूँद, सरणी बफ़र्स की आवश्यकता होती है, आप हेडर सेट कर सकते हैं, mimetype को ओवरराइड कर सकते हैं और बहुत कुछ है ...
लेकिन यहाँ सवाल यह है कि अजाक्स प्रतिक्रिया कैसे दी जाए ... (मैंने एक आसान तरीका जोड़ा।)
यदि आप वादों का उपयोग कर रहे हैं, तो यह उत्तर आपके लिए है।
इसका मतलब है AngularJS, jQuery (आस्थगित के साथ), देशी XHR के प्रतिस्थापन (लाने), EmberJS, BackboneJS की बचत या कोई भी नोड लाइब्रेरी जो वादे लौटाती है।
आपका कोड इस की तर्ज पर कुछ होना चाहिए:
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 का उपयोग करने वाले लोगों के लिए एक अच्छा जवाब लिखने का काम किया। मेरे पास देशी XHR का उत्तर है। यह जवाब या तो फ्रंटएंड या बैकएंड पर वादों के सामान्य उपयोग के लिए है।
मूल मुद्दा है
ब्राउज़र में जावास्क्रिप्ट कॉन्सेप्ट मॉडल और NodeJS / 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, सर्वर कॉल, IO, टाइमर) आप मूल्य वापस कर रहे हैं इससे पहले कि अनुरोध को आपके कोड को बताने का मौका मिला कि वह मूल्य क्या है।
इस समस्या का एक संभावित समाधान यह है कि जब गणना पूरी हो जाए तो अपने कार्यक्रम को फिर से सक्रिय रूप से कोड करें। वादे सक्रिय रूप से (समय के प्रति संवेदनशील) स्वभाव में होने से इसे सक्षम करते हैं।
वादों पर त्वरित टालमटोल
एक वादा समय के साथ एक मूल्य है । वादे की स्थिति होती है, वे बिना किसी मूल्य के लंबित होने लगते हैं और इसके लिए तैयार हो सकते हैं:
- पूरा जिसका अर्थ है कि गणना सफलतापूर्वक पूर्ण हुआ।
- अस्वीकार कर दिया कि अभिकलन विफल हो गया।
एक वादा केवल एक बार राज्यों को बदल सकता है जिसके बाद वह हमेशा एक ही राज्य में रहेगा। आप then
अपने मूल्य निकालने और त्रुटियों को संभालने के वादे के लिए हैंडलर संलग्न कर सकते हैं। then
हैंडलर कॉल को चैन करने की अनुमति देते हैं। वादे एपीआई का उपयोग करके बनाए जाते हैं जो उन्हें वापस करते हैं । उदाहरण के लिए, अधिक आधुनिक 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
।
इसे लागू करना
यह आपकी मूल API कॉल के लिए समान है, आप यह कर सकते हैं:
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)
ES6 जनरेटर का परिचय देता है जो ऐसे कार्य हैं जो बीच में लौट सकते हैं और फिर उस बिंदु को फिर से शुरू कर सकते हैं जो वे थे। उदाहरणों के लिए, यह आम तौर पर उपयोगी होता है:
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)
ES7 में, इसे और मानकीकृत किया गया है, अभी कई प्रस्ताव हैं लेकिन उन सभी में आप await
वादा कर सकते हैं । यह ऊपर async
और await
कीवर्ड जोड़कर ES6 प्रस्ताव के लिए सिर्फ "चीनी" (अच्छे वाक्यविन्यास) है । उपरोक्त उदाहरण बनाना:
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
}
यह अभी भी एक ही वादा करता है :)
आप अजाक्स का गलत उपयोग कर रहे हैं। विचार यह नहीं है कि इसे कुछ भी लौटाया जाए, बल्कि डेटा को कॉलबैक फ़ंक्शन नाम की चीज़ को सौंप दिया जाए, जो डेटा को संभालता है।
अर्थात्:
function handleData( responseData ) {
// Do what you want with the data
console.log(responseData);
}
$.ajax({
url: "hi.php",
...
success: function ( data, status, XHR ) {
handleData(data);
}
});
सबमिट हैंडलर में कुछ भी लौटाने से कुछ नहीं होगा। आपको इसके बजाय या तो डेटा को बंद करना होगा, या आप जो चाहते हैं, उसे सीधे सफलता के समारोह में ले जाना चाहिए।
सरलतम समाधान जावास्क्रिप्ट फ़ंक्शन बनाता है और इसे अजाक्स 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);
});
मैं एक भयानक-दिखने वाले, हाथ से तैयार कॉमिक के साथ जवाब दूंगा। दूसरी छवि यही कारण है कि आपके कोड उदाहरण में क्यों result
है undefined
।
कोणीय १
जो लोग AngularJS का उपयोग कर रहे हैं , वे इस स्थिति का उपयोग करके संभाल सकते हैं Promises
।
यहाँ यह कहता है,
वादों को अतुल्यकालिक कार्यों के लिए इस्तेमाल किया जा सकता है और एक साथ कई कार्यों को चेन करने की अनुमति देता है।
आप यहाँ एक अच्छी व्याख्या भी पा सकते हैं ।
उदाहरण नीचे दिए गए डॉक्स में मिला ।
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
निम्नलिखित उदाहरण को देखो, लेकिन इसके साथ की सिफारिश की उपयोग करने के लिए 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));
}
मूल पोस्ट यहाँ देखें । लेकिन टाइपस्क्रिप्ट देशी es6 वादों का समर्थन नहीं करता है , यदि आप इसका उपयोग करना चाहते हैं, तो आपको इसके लिए प्लगइन की आवश्यकता हो सकती है।
इसके अतिरिक्त यहाँ वादे युक्ति यहाँ परिभाषित है।
यहाँ पर अधिकांश उत्तर आपके लिए एक एकल async ऑपरेशन होने पर उपयोगी सुझाव देते हैं, लेकिन कभी-कभी, यह तब आता है जब आपको किसी सरणी या अन्य सूची जैसी संरचना में प्रत्येक प्रविष्टि के लिए एक अतुल्यकालिक ऑपरेशन करने की आवश्यकता होती है। प्रलोभन यह करना है:
// 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
तक आप परिणामों का उपयोग करने की कोशिश कर रहे हैं तब तक कॉलबैक अभी तक नहीं चला है।
इसलिए, यदि आपके पास एक सरणी (या किसी प्रकार की सूची) है और प्रत्येक प्रविष्टि के लिए async संचालन करना चाहते हैं, तो आपके पास दो विकल्प हैं: ऑपरेशन को समानांतर (ओवरलैपिंग) में करें, या श्रृंखला में (क्रम में एक के बाद एक) करें।
समानांतर
आप उन सभी को शुरू कर सकते हैं और आप कितने कॉलबैक की उम्मीद कर रहे हैं, इसका ट्रैक रख सकते हैं, और जब आपने कई कॉलबैक प्राप्त कर लिए हैं तो परिणामों का उपयोग करें:
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
से forEach
में परिणाम को बचाने के लिए results
प्रविष्टि यह से संबंधित है के रूप में एक ही स्थिति में है, भले ही परिणाम के आदेश से बाहर आने (async कॉल क्रम में जरूरी पूरा नहीं करते हैं, क्योंकि वे शुरू किए गए, जिसमें)।
लेकिन क्या होगा अगर आपको एक फ़ंक्शन से उन परिणामों को वापस करने की आवश्यकता है ? जैसा कि अन्य उत्तरों ने बताया है, आप नहीं कर सकते हैं; आपको अपना फ़ंक्शन स्वीकार करना होगा और कॉलबैक (या एक वादा वापस करना ) करना होगा। यहाँ एक कॉलबैक संस्करण है:
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
आप एक वादा देता है , तो आप उपयोग कर सकते हैं Promise.all:
function doSomethingWith(theArray) {
return Promise.all(theArray.map(function(entry) {
return doSomethingAsync(entry);
}));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
यदि आप जानते हैं कि doSomethingAsync
एक दूसरे और तीसरे तर्क को नजरअंदाज करेंगे, तो आप इसे सीधे पास कर सकते हैं map
( map
इसके कॉलबैक को तीन तर्कों के साथ, लेकिन ज्यादातर लोग केवल पहले समय का उपयोग करते हैं):
function doSomethingWith(theArray) {
return Promise.all(theArray.map(doSomethingAsync));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
उदाहरण:
function doSomethingWith(theArray) {
return Promise.all(theArray.map(doSomethingAsync));
}
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
आप एक वादा देता है, यदि आप ES2017 + वाक्य रचना (शायद की तरह एक transpiler साथ उपयोग कर सकते हैं कोलाहल ), आप एक का उपयोग कर सकते asyncसमारोह के साथ 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;
}
इस उदाहरण पर एक नज़र डालें:
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
कि एक हल किया हुआ वादा वापस आ रहा है (यह वापस आते समय हल हो गया है res.data.value
)। इसलिए आप तब तक प्रतीक्षा करते हैं जब तक $ http.get अनुरोध पूरा नहीं हो जाता है और फिर कंसोल .log (res.joke) निष्पादित हो जाता है (एक सामान्य एसिंक्रोनस प्रवाह के रूप में)।
यह तख्ती है:
http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/
ES6 रास्ता (async - प्रतीक्षा)
(function(){
async function getJoke(){
let response = await fetch('http://api.icndb.com/jokes/random');
let data = await response.json();
return data.value;
}
getJoke().then((joke) => {
console.log(joke);
});
})();
यह उन स्थानों में से एक है जो दो तरह से डेटा बाइंडिंग या स्टोर अवधारणा है जो कई नए जावास्क्रिप्ट फ्रेमवर्क में उपयोग किया जाता है, आपके लिए बहुत अच्छा काम करेगा ...
इसलिए यदि आप Angular, React या किसी अन्य चौखटे का उपयोग कर रहे हैं , जो दो तरीके से डेटा बाइंडिंग या स्टोर कॉन्सेप्ट करता है, तो यह समस्या केवल आपके लिए तय है, इसलिए आसान शब्दों में, आपका परिणाम undefined
पहले चरण में है, इसलिए result = undefined
आपको प्राप्त करने से पहले आपको प्राप्त करना होगा। डेटा, फिर जैसे ही आप परिणाम प्राप्त करते हैं, इसे अपडेट किया जाएगा और नए मूल्य पर असाइन किया जाएगा जो आपके अजाक्स कॉल की प्रतिक्रिया ...
लेकिन आप इसे उदाहरण के लिए शुद्ध जावास्क्रिप्ट या jQuery में कैसे कर सकते हैं जैसा कि आपने इस प्रश्न में पूछा है?
आप कॉलबैक का उपयोग कर सकते हैं , वादा कर सकते हैं और हाल ही में आपके लिए इसे संभालने के लिए अवलोकन कर सकते हैं, उदाहरण के लिए वादों में हमारे पास कुछ फ़ंक्शन हैं जैसे success()
या then()
जिसे तब निष्पादित किया जाएगा जब आपका डेटा आपके लिए तैयार हो, उसी तरह कॉलबैक या अवलोकन योग्य फ़ंक्शन पर सदस्यता लें ।
उदाहरण के लिए आपके मामले में जो आप 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
});
अधिक जानकारी के लिए वादों और वेधशालाओं के बारे में अध्ययन करें जो इस async सामान को करने के लिए नए तरीके हैं।
यह एक बहुत ही सामान्य मुद्दा है जिसका सामना हम जावास्क्रिप्ट के 'रहस्यों' से करते हुए करते हैं। मुझे आज इस रहस्य को ध्वस्त करने की कोशिश करें।
चलो एक सरल जावास्क्रिप्ट फ़ंक्शन के साथ शुरू करते हैं:
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
), लेकिन यह एक टाइमर शुरू करता है, जो 'वोह' को वापस करने के लिए 1s के बाद एक फ़ंक्शन निष्पादित करता है। लेकिन जैसा कि आप देख सकते हैं, बार को सौंपा गया मान फू () से तुरंत लौटा हुआ सामान है, जो कि कुछ भी नहीं है undefined
।
तो, हम इस मुद्दे से कैसे निपटेंगे?
आइए एक PROMISE के लिए हमारे फ़ंक्शन से पूछें । वादा वास्तव में इसका क्या मतलब है: इसका मतलब है कि फ़ंक्शन आपको भविष्य में मिलने वाले किसी भी आउटपुट के साथ प्रदान करने की गारंटी देता है। तो चलिए इसे ऊपर की हमारी छोटी समस्या के लिए देखते हैं:
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 saveUsers(){
getUsers()
.then(users => {
saveSomewhere(users);
})
.catch(err => {
console.error(err);
})
}
async / प्रतीक्षा संस्करण:
async function saveUsers(){
try{
let users = await getUsers()
saveSomewhere(users);
}
catch(err){
console.error(err);
}
}
एक एसिंक्रोनस फ़ंक्शन से मान वापस करने के लिए एक और दृष्टिकोण, एक ऑब्जेक्ट में पास करना है जो परिणाम को एसिंक्रोनस फ़ंक्शन से संग्रहीत करेगा।
यहाँ उसी का एक उदाहरण दिया गया है:
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
अतुल्यकालिक ऑपरेशन के दौरान मूल्य को स्टोर करने के लिए ऑब्जेक्ट का उपयोग कर रहा हूं । यह परिणाम को अतुल्यकालिक नौकरी के बाद भी उपलब्ध होने की अनुमति देता है।
मैं इस दृष्टिकोण का उपयोग करता हूं। मुझे यह जानने में दिलचस्पी होगी कि यह दृष्टिकोण कितना अच्छा काम करता है जहां लगातार मॉड्यूल के माध्यम से परिणाम को वापस लाना शामिल है।
जबकि वादे और कॉलबैक कई स्थितियों में ठीक काम करते हैं, यह कुछ इस तरह व्यक्त करने के लिए पीछे का दर्द है:
if (!name) {
name = async1();
}
async2(name);
आप अंत तक जाना चाहते हैं async1
; जाँच करें कि name
क्या अपरिभाषित है या नहीं और तदनुसार कॉलबैक कॉल करें।
async1(name, callback) {
if (name)
callback(name)
else {
doSomething(callback)
}
}
async1(name, async2)
जबकि छोटे उदाहरणों में यह ठीक है , जब आपको बहुत सारे ऐसे ही मामले और त्रुटि से निपटने में गुस्सा आता है।
Fibers
समस्या को हल करने में मदद करता है।
var Fiber = require('fibers')
function async1(container) {
var current = Fiber.current
var result
doSomething(function(name) {
result = name
fiber.run()
})
Fiber.yield()
return result
}
Fiber(function() {
var name
if (!name) {
name = async1()
}
async2(name)
// Make any number of async calls from here
}
आप यहां प्रोजेक्ट चेकआउट कर सकते हैं ।
निम्नलिखित उदाहरण मैंने लिखा है कि कैसे
- अतुल्यकालिक HTTP कॉल संभालें;
- प्रत्येक एपीआई कॉल से प्रतिक्रिया की प्रतीक्षा करें;
- प्रॉमिस पैटर्न का उपयोग करें ;
- कई HTTP कॉल में शामिल होने के लिए Promise.all पैटर्न का उपयोग करें ;
यह काम करने का उदाहरण आत्म-निहित है। यह एक साधारण अनुरोध ऑब्जेक्ट को परिभाषित करेगा XMLHttpRequest
जो कॉल करने के लिए विंडो ऑब्जेक्ट का उपयोग करता है । वादों का एक गुच्छा पूरा होने के लिए प्रतीक्षा करने के लिए यह एक सरल कार्य को परिभाषित करेगा।
प्रसंग। क्वेरी स्ट्रिंग्स के दिए गए सेट के लिए ऑब्जेक्ट खोजने के लिए उदाहरण Spotify Web API एंडपॉइंट playlist
को क्वेरी कर रहा है:
[
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]
प्रत्येक आइटम के लिए, एक नया वादा एक ब्लॉक को आग देगा - ExecutionBlock
परिणाम को पार्स करें, परिणाम सरणी के आधार पर वादों के एक नए सेट को शेड्यूल करें, जो कि Spotify user
ऑब्जेक्ट्स की एक सूची है और ExecutionProfileBlock
अतुल्यकालिक रूप से नए HTTP कॉल को निष्पादित करें ।
आप तब एक नेस्टेड प्रोमिस संरचना देख सकते हैं, जो आपको एकाधिक और पूरी तरह से अतुल्यकालिक नेस्टेड HTTP कॉल को स्पॉन करने देता है, और कॉल के प्रत्येक सबसेट से परिणामों में शामिल होता है Promise.all
।
नोट हाल ही में Spotify search
API को अनुरोध हेडर में निर्दिष्ट टोकन की आवश्यकता होगी:
-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" />
मैंने इस समाधान की यहाँ व्यापक चर्चा की है ।
संक्षिप्त उत्तर है, आपको इस तरह से कॉलबैक लागू करना होगा:
function callback(response) {
// Here you can do what ever you want with the response object.
console.log(response);
}
$.ajax({
url: "...",
success: callback
});
2017 का उत्तर: आप अब वही कर सकते हैं जो आप हर वर्तमान ब्राउज़र और नोड में चाहते हैं
यह काफी सरल है:
- एक वादा वापस करो
- 'प्रतीक्षा' का उपयोग करें , जो जावास्क्रिप्ट को मूल्य में हल किए जाने वाले वादे का इंतजार करने के लिए बताएगा (जैसे HTTP प्रतिक्रिया)
- मूल फ़ंक्शन में 'async' कीवर्ड जोड़ें
यहां आपके कोड का एक कार्यशील संस्करण है:
(async function(){
var response = await superagent.get('...')
console.log(response)
})()
इंतजार सभी वर्तमान ब्राउज़रों और नोड 8 में समर्थित है
Js एक एकल पिरोया हुआ है।
ब्राउज़र को तीन भागों में विभाजित किया जा सकता है:
1) इवेंट लूप
2) वेब एपीआई
3) इवेंट कतार
ईवेंट लूप हमेशा के लिए चलता है। एक प्रकार का अनंत लूप। ईवेंट क्यू है, जहां आपके सभी फ़ंक्शन को किसी घटना पर धकेल दिया जाता है (उदाहरण: क्लिक करें) यह एक के बाद एक कतार से बाहर किया जाता है और ईवेंट लूप में डाला जाता है जो इस फ़ंक्शन को निष्पादित करता है और स्वयं को तैयार करता है पहले एक के बाद एक के लिए निष्पादित किया जाता है। इसका मतलब है कि एक फ़ंक्शन का निष्पादन फ़ंक्शन तक शुरू नहीं होता है जब तक कि कतार में इसे क्रियान्वित नहीं किया जाता है।
अब हमें लगता है कि हमने एक कतार में दो कार्यों को धकेल दिया है एक सर्वर से डेटा प्राप्त करने के लिए है और दूसरा उस डेटा का उपयोग करता है। हमने पहले सर्वर का उपयोग किया। serverRequest फ़ंक्शन ईवेंट लूप में जाता है और सर्वर को कॉल करता है क्योंकि हमें कभी नहीं पता होता है कि सर्वर से डेटा प्राप्त करने में कितना समय लगेगा, इसलिए इस प्रक्रिया में समय लगने की उम्मीद है और इसलिए हम अपने ईवेंट लूप में व्यस्त रहते हैं, इस प्रकार हमारा पेज हैंग हो जाता है, जहां वेब है API भूमिका में आता है और इस फ़ंक्शन को इवेंट लूप से लेता है और सर्वर के साथ इवेंट लूप को निःशुल्क करता है ताकि हम कतार से अगले फ़ंक्शन को निष्पादित कर सकें। कतार में अगला फ़ंक्शन उपयोग है () अगले समारोह की बर्बादी और निष्पादन कतार के अंत तक जारी रहता है। (इसे Async कॉलिंग कहा जाता है। हम कुछ और कर सकते हैं जब तक हम डेटा प्राप्त नहीं करते हैं)
मान लें कि हमारे serverRequest () फ़ंक्शन में एक कोड में रिटर्न स्टेटमेंट था, जब हमें सर्वर से डेटा वापस मिलता है तो वेब एपीआई इसे कतार के अंत में कतार में धकेल देगा। चूंकि यह कतार में अंत में धकेल दिया जाता है इसलिए हम इसके डेटा का उपयोग नहीं कर सकते क्योंकि इस डेटा का उपयोग करने के लिए हमारी कतार में कोई फ़ंक्शन नहीं बचा है। इस प्रकार Async Call से कुछ वापस करना संभव नहीं है।
इस प्रकार इसका समाधान कॉलबैक या वादा है ।
यहाँ एक उत्तर से एक छवि, सही ढंग से कॉलबैक उपयोग की व्याख्या करती है ... हम अपने फ़ंक्शन (सर्वर से लौटे डेटा का उपयोग कर रहे हैं) को कॉलिंग सर्वर को कार्य करने के लिए देते हैं।
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");
}
Javscript.info कॉलबैक
आप रिमोट कॉल करने के लिए इस कस्टम लाइब्रेरी (प्रोमिस का उपयोग करते हुए लिखे गए) का उपयोग कर सकते हैं।
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)
});
एक अन्य समाधान अनुक्रमिक निष्पादक 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. nsynjs के माध्यम से तुल्यकालिक तरीके से फ़ंक्शन चलाएँ:
nsynjs.run(process,this,function () {
console.log("synchronous function finished");
});
अगर कुछ धीमी गति से कार्य करने का परिणाम तैयार नहीं है, तो एनएसजीएनजे सभी ऑपरेटरों और भावों का मूल्यांकन करेगा।
अधिक उदाहरण यहाँ: https://github.com/amaksr/nsynjs/tree/master/examples
ECMAScript 6 में 'जनरेटर' हैं जो आपको एक अतुल्यकालिक शैली में आसानी से कार्यक्रम करने की अनुमति देते हैं।
function* myGenerator() {
const callback = yield;
let [response] = yield $.ajax("https://stackoverflow.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);
अतुल्यकालिक अनुरोधों के साथ काम करने के लिए यहां कुछ दृष्टिकोण दिए गए हैं:
- ब्राउज़र वादा वस्तु
- क्यू - जावास्क्रिप्ट के लिए एक वादा पुस्तकालय
- A + वादा करता है। Js
- jQuery स्थगित
- XMLHttpRequest एपीआई
- कॉलबैक अवधारणा का उपयोग करना - पहले उत्तर में कार्यान्वयन के रूप में
उदाहरण: कई अनुरोधों के साथ काम करने के लिए 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();
हम खुद को एक ऐसे ब्रह्मांड में पाते हैं जो एक आयाम के साथ प्रगति करता है जिसे हम "समय" कहते हैं। हम वास्तव में नहीं समझते हैं कि समय क्या है, लेकिन हमने अमूर्तता और शब्दावली विकसित की है जो हमें इसका कारण और बात करते हैं: "अतीत", "वर्तमान", "भविष्य", "पहले", "बाद"।
कंप्यूटर सिस्टम जो हम बनाते हैं - अधिक से अधिक - एक महत्वपूर्ण आयाम के रूप में समय है। भविष्य में होने के लिए कुछ चीजें निर्धारित की जाती हैं। फिर अन्य चीजों को पहले उन चीजों के बाद होने की आवश्यकता होती है जो अंततः होती हैं। यह "एसिंक्रोनसिटी" नामक मूल धारणा है। हमारी बढ़ती नेटवर्क दुनिया में, अतुल्यकालिकता का सबसे आम मामला कुछ अनुरोधों का जवाब देने के लिए किसी दूरस्थ प्रणाली की प्रतीक्षा कर रहा है।
एक उदाहरण पर विचार करें। आप दूधवाले को बुलाते हैं और कुछ दूध मंगवाते हैं। जब यह आता है, तो आप इसे अपनी कॉफी में डालना चाहते हैं। आप अभी अपनी कॉफी में दूध नहीं डाल सकते हैं, क्योंकि यह अभी तक यहां नहीं है। आपको इसे अपनी कॉफी में डालने से पहले आने का इंतजार करना होगा। दूसरे शब्दों में, निम्नलिखित काम नहीं करेगा:
var milk = order_milk();
put_in_coffee(milk);
क्योंकि जे एस कोई रास्ता नहीं पता है कि यह करने की जरूरत है इंतज़ार के लिए order_milk
इससे पहले कि यह कार्यान्वित समाप्त करने के लिए put_in_coffee
। दूसरे शब्दों में, यह पता नहीं है कि order_milk
है अतुल्यकालिक --is कुछ है कि कुछ भविष्य समय तक दूध में परिणाम के लिए नहीं जा रहा है। जेएस, और अन्य घोषणात्मक भाषाएं प्रतीक्षा किए बिना एक के बाद एक बयान निष्पादित करती हैं।
इस समस्या के बारे में क्लासिक जेएस दृष्टिकोण, इस तथ्य का लाभ उठाते हुए कि जेएस प्रथम श्रेणी की वस्तुओं के रूप में कार्यों का समर्थन करता है, जिसे पास किया जा सकता है, अतुल्यकालिक अनुरोध के पैरामीटर के रूप में एक फ़ंक्शन पास करना है, जो तब पूरा होगा जब यह पूरा हो जाएगा। भविष्य में कभी-कभी इसका कार्य। यह "कॉलबैक" दृष्टिकोण है। यह इस तरह दिख रहा है:
order_milk(put_in_coffee);
order_milk
बंद करता है, दूध का आदेश देता है, तब, जब और केवल जब यह आता है, यह आह्वान करता है put_in_coffee
।
इस कॉलबैक दृष्टिकोण के साथ समस्या यह है कि यह किसी फ़ंक्शन के सामान्य शब्दार्थ को प्रदूषित करता है, जिसके परिणाम की रिपोर्ट करता है return
; इसके बजाय, फ़ंक्शंस को पैरामीटर के रूप में दिए गए कॉलबैक पर कॉल करके उनके परिणामों की रिपोर्ट नहीं करनी चाहिए। इसके अलावा, घटनाओं के लंबे दृश्यों के साथ काम करते समय यह दृष्टिकोण तेजी से कम हो सकता है। उदाहरण के लिए, मान लें कि मैं कॉफी में दूध डालने का इंतजार करना चाहता हूं, और उसके बाद ही कॉफी पीने के बाद तीसरा कदम उठाता हूं। मुझे इस तरह से कुछ लिखने की आवश्यकता है:
order_milk(function(milk) { put_in_coffee(milk, drink_coffee); }
जहाँ मैं put_in_coffee
दूध डालने के लिए दोनों को पास कर रहा हूँ , और drink_coffee
दूध डालने के बाद एक बार निष्पादित करने की क्रिया ( ) भी ।
इस मामले में, हम प्रश्न में कोड को फिर से लिख सकते हैं:
var answer;
$.ajax('/foo.json') . done(function(response) {
callback(response.data);
});
function callback(data) {
console.log(data);
}
वादे दर्ज करें
यह एक "वादा" की धारणा के लिए प्रेरणा थी, जो एक विशेष प्रकार का मूल्य है जो किसी प्रकार के भविष्य या अतुल्यकालिक परिणाम का प्रतिनिधित्व करता है । यह उस चीज़ का प्रतिनिधित्व कर सकता है जो पहले से ही हुआ है, या जो भविष्य में होने वाला है, या कभी भी ऐसा नहीं हो सकता है। वादों की एक एकल विधि है, जिसका नाम है then
, जिसमें आप वादे को पूरा करने के लिए एक कार्यवाही करते हैं, जब वादे का प्रतिनिधित्व किया जाता है।
हमारे दूध और कॉफी के मामले में, हम order_milk
दूध के आगमन के लिए एक वादा वापस करने के लिए डिज़ाइन करते हैं, फिर put_in_coffee
एक then
कार्रवाई के रूप में निर्दिष्ट करते हैं:
order_milk() . then(put_in_coffee)
इसका एक फायदा यह है कि हम भविष्य में होने वाली घटनाओं ("चैनिंग") के अनुक्रम बनाने के लिए इन्हें एक साथ जोड़ सकते हैं:
order_milk() . then(put_in_coffee) . then(drink_coffee)
आइए अपनी विशेष समस्या के लिए वादों को लागू करें। हम एक फ़ंक्शन के अंदर अपने अनुरोध तर्क को लपेटेंगे, जो एक वादा लौटाता है:
function get_data() {
return $.ajax('/foo.json');
}
दरअसल, हमने जो कुछ भी किया है return
वह कॉल टू में जोड़ा गया है $.ajax
। यह काम करता है क्योंकि jQuery $.ajax
पहले से ही एक तरह का वादा जैसी चीज़ लौटाता है। (व्यवहार में, विवरण में शामिल हुए बिना, हम इस कॉल को लपेटना पसंद करेंगे ताकि वास्तविक वादा वापस कर सकें, या ऐसा करने के लिए कुछ विकल्प का उपयोग $.ajax
करें।) अब, यदि हम फ़ाइल को लोड करना चाहते हैं और इसके खत्म होने की प्रतीक्षा करें और तो कुछ करो, हम बस कह सकते हैं
get_data() . then(do_something)
मिसाल के तौर पर,
get_data() .
then(function(data) { console.log(data); });
वादों का उपयोग करते समय, हम बहुत सारे कार्यों को समाप्त कर देते हैं then
, इसलिए अक्सर अधिक कॉम्पैक्ट ES6- शैली तीर फ़ंक्शन का उपयोग करना उपयोगी होता है:
get_data() .
then(data => console.log(data));
async
कीवर्ड
लेकिन वहाँ अभी भी कुछ अस्पष्ट रूप से कोड एक तरह से लिखने के बारे में असंतुष्ट है अगर तुल्यकालिक और एक बहुत अलग तरीका है अगर अतुल्यकालिक। तुल्यकालिक के लिए, हम लिखते हैं
a();
b();
लेकिन अगर a
अतुल्यकालिक है, तो वादों के साथ हमें लिखना होगा
a() . then(b);
ऊपर, हमने कहा, "जेएस के पास यह जानने का कोई तरीका नहीं है कि दूसरे को निष्पादित करने से पहले इसे समाप्त करने के लिए पहले कॉल की प्रतीक्षा करने की आवश्यकता है "। अगर जेएस को यह बताने का कोई तरीका होता तो अच्छा नहीं होता ? यह पता चला है कि await
एक विशेष प्रकार के फ़ंक्शन के अंदर उपयोग किया जाने वाला कीवर्ड "async" फ़ंक्शन है। यह सुविधा ES के आगामी संस्करण का हिस्सा है, लेकिन पहले से ही ट्रांसपॉयलर में उपलब्ध है जैसे कि बाबेल ने सही प्रीसेट दिए हैं। यह हमें बस लिखने की अनुमति देता है
async function morning_routine() {
var milk = await order_milk();
var coffee = await put_in_coffee(milk);
await drink(coffee);
}
आपके मामले में, आप कुछ ऐसा लिख सकेंगे
async function foo() {
data = await get_data();
console.log(data);
}
संक्षिप्त उत्तर : आपका foo()
तरीका तुरंत वापस आ जाता है, जबकि $ajax()
कॉल फंक्शन के बाद एसिंक्रोनस रूप से निष्पादित होता है । समस्या तब होती है कि कैसे या कहाँ से पुन: प्राप्त होने पर एस्किंस कॉल द्वारा प्राप्त परिणामों को संग्रहीत किया जाए।
इस सूत्र में कई समाधान दिए गए हैं। शायद सबसे आसान तरीका किसी ऑब्जेक्ट को foo()
विधि से गुजारना है, और async कॉल पूरा होने के बाद उस ऑब्जेक्ट के सदस्य में परिणामों को संग्रहीत करना है।
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
।
सफलता के 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();
वादा का उपयोग करना
इस सवाल का सबसे सही जवाब उपयोग कर रहा है Promise
।
function ajax(method, url, params) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open(method, url);
xhr.send(params);
});
}
प्रयोग
ajax("GET", "/test", "acrive=1").then(function(result) {
// Code depending on result
})
.catch(function() {
// An error occurred
});
पर रुको...!
वादों का उपयोग करने में समस्या है!
हमें अपने कस्टम प्रॉमिस का उपयोग क्यों करना चाहिए?
मैं कुछ समय के लिए इस समाधान का उपयोग कर रहा था जब तक मुझे लगा कि पुराने ब्राउज़रों में कोई त्रुटि है:
Uncaught ReferenceError: Promise is not defined
इसलिए मैंने अपने संकलित वर्ग को ES3 के लिए js संकलक से नीचे लागू करने का निर्णय लिया, यदि वह परिभाषित नहीं है। बस अपने मुख्य कोड से पहले इस कोड को जोड़ें और फिर सुरक्षित रूप से प्रोमिस का उपयोग करें!
if(typeof Promise === "undefined"){
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Promise = function () {
function Promise(main) {
var _this = this;
_classCallCheck(this, Promise);
this.value = undefined;
this.callbacks = [];
var resolve = function resolve(resolveValue) {
_this.value = resolveValue;
_this.triggerCallbacks();
};
var reject = function reject(rejectValue) {
_this.value = rejectValue;
_this.triggerCallbacks();
};
main(resolve, reject);
}
Promise.prototype.then = function then(cb) {
var _this2 = this;
var next = new Promise(function (resolve) {
_this2.callbacks.push(function (x) {
return resolve(cb(x));
});
});
return next;
};
Promise.prototype.catch = function catch_(cb) {
var _this2 = this;
var next = new Promise(function (reject) {
_this2.callbacks.push(function (x) {
return reject(cb(x));
});
});
return next;
};
Promise.prototype.triggerCallbacks = function triggerCallbacks() {
var _this3 = this;
this.callbacks.forEach(function (cb) {
cb(_this3.value);
});
};
return Promise;
}();
}
सवाल यह था:
मैं एसिंक्रोनस कॉल से प्रतिक्रिया कैसे लौटाऊं?
जिसकी व्याख्या इस प्रकार की जा सकती है:
कैसे बनाने के लिए अतुल्यकालिक कोड नज़र तुल्यकालिक ?
समाधान कॉलबैक से बचने के लिए होगा, और वादों और async / प्रतीक्षा के संयोजन का उपयोग करना होगा ।
मैं एक अजाक्स अनुरोध के लिए एक उदाहरण देना चाहूंगा।
(हालांकि यह जावास्क्रिप्ट में लिखा जा सकता है, मैं इसे पायथन में लिखना पसंद करता हूं, और इसे ट्रांसक्रिप्ट का उपयोग करके जावास्क्रिप्ट में संकलित करना चाहता हूं । यह पर्याप्त स्पष्ट होगा।)
पहले 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")
बेशक, कई दृष्टिकोण हैं जैसे कि तुल्यकालिक अनुरोध, वादा, लेकिन मेरे अनुभव से मुझे लगता है कि आपको कॉलबैक दृष्टिकोण का उपयोग करना चाहिए। यह जावास्क्रिप्ट के अतुल्यकालिक व्यवहार के लिए स्वाभाविक है। तो, आपका कोड स्निपेट थोड़ा अलग हो सकता है:
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
myCallback(response);
}
});
return result;
}
function myCallback(response) {
// Does something.
}
यहां और मेरे अनुभवों के साथ सभी प्रतिक्रियाओं को पढ़ने के बाद, मैं callback, promise and async/await
जावास्क्रिप्ट में अतुल्यकालिक प्रोग्रामिंग के लिए विस्तार को फिर से शुरू करना चाहूंगा ।
1) कॉलबैक: कॉलबैक का मूल कारण किसी घटना के जवाब में कोड चलाना है (नीचे उदाहरण देखें)। हम हर बार जावास्क्रिप्ट में कॉलबैक का उपयोग करते हैं।
const body = document.getElementsByTagName('body')[0];
function callback() {
console.log('Hello');
}
body.addEventListener('click', callback);
लेकिन अगर आपको नीचे दिए गए उदाहरण में कई नेस्टेड कॉलबैक का उपयोग करना चाहिए, तो यह कोड रीफैक्टरिंग के लिए बहुत भयानक होगा।
asyncCallOne(function callback1() {
asyncCallTwo(function callback2() {
asyncCallThree(function callback3() {
...
})
})
})
2) वादा: एक वाक्यविन्यास ES6 - वादा कॉलबैक नरक मुद्दे को हल करता है!
const myFirstPromise = new Promise((resolve, reject) => {
// We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
// In this example, we use setTimeout(...) to simulate async code.
// In reality, you will probably be using something like XHR request or an HTML5 API.
setTimeout(() => {
resolve("Success!") // Yay! Everything went well!
}, 250)
})
myFirstPromise
.then((res) => {
return res.json();
})
.then((data) => {
console.log(data);
})
.catch((e) => {
console.log(e);
});
myFirstPromise एक वादा उदाहरण है जो async कोड की प्रक्रिया का प्रतिनिधित्व करता है। संकल्प फ़ंक्शन संकेत देता है कि वादा उदाहरण समाप्त हो गया है। बाद में, हम .then () (.then की एक श्रृंखला जैसा आप चाहते हैं) और .चेक () वादे पर काम कर सकते हैं:
then — Runs a callback you pass to it when the promise has fulfilled.
catch — Runs a callback you pass to it when something went wrong.
3) Async / Await: एक नया वाक्यविन्यास ES6 - Await मूल रूप से वादा के चीनी वाक्य रचना है!
Async फ़ंक्शन हमें एक साफ और संक्षिप्त सिंटैक्स प्रदान करता है जो हमें वादों के साथ प्राप्त होने वाले समान परिणाम को पूरा करने के लिए कम कोड लिखने में सक्षम बनाता है। Async / Await सिंक्रोनस कोड के समान दिखता है , और सिंक्रोनस कोड पढ़ना और लिखना बहुत आसान है। Async / Await के साथ त्रुटियों को पकड़ने के लिए, हम ब्लॉक का उपयोग कर सकते हैं try...catch
। यहाँ, आपको प्रॉमिस सिंटैक्स की .then () श्रृंखला लिखने की आवश्यकता नहीं है।
const getExchangeRate = async () => {
try {
const res = await fetch('https://getExchangeRateData');
const data = await res.json();
console.log(data);
} catch (err) {
console.error(err);
}
}
getExchangeRate();
निष्कर्ष: ये जावास्क्रिप्ट में अतुल्यकालिक प्रोग्रामिंग के लिए पूरी तरह से तीन वाक्यविन्यास हैं जिन्हें आप अच्छी तरह समझते हैं। इसलिए यदि संभव हो, तो मैं सलाह देता हूं कि आपको अपने अतुल्यकालिक कोड (ज्यादातर एक्सएचआर अनुरोधों के लिए) को फिर से लाने के लिए "वादे" या "एसिंक्स / वेट" का उपयोग करना चाहिए !
आप पर कोड फेंकने के बजाय, 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 का उपयोग करके कॉल करते हैं या कोई अतुल्यकालिक कोड (उदाहरण के लिए एक सेटटाइमआउट) चलाते हैं, तो आगे बढ़ने से पहले जावास्क्रिप्ट एक प्रतिक्रिया पर निर्भर होता है।
बड़ा सवाल यह है कि इसे प्रतिक्रिया कब मिलेगी? इसका उत्तर हमें नहीं पता है - इसलिए इवेंट लूप उस संदेश का इंतजार कर रहा है जब वह कहता है "अरे मुझे चला"। यदि JS सिर्फ उस संदेश के लिए प्रतीक्षा कर रहा है, तो आपका एप्लिकेशन समकालिक रूप से जम जाएगा और यह बेकार हो जाएगा। इसलिए JS कतार में अगली वस्तु को क्रियान्वित करने के लिए संदेश के इंतज़ार में कतार में लग जाता है।
इसलिए अतुल्यकालिक कार्यक्षमता के साथ हम कॉलबैक नामक चीजों का उपयोग करते हैं । यह काफी वादे की तरह थोड़े है । जैसा कि मैं कुछ बिंदु पर कुछ वापस करने का वादा करता हूं jQuery विशिष्ट कॉलबैक का उपयोग करता है जिसे ( deffered.done
deffered.fail
और deffered.always
दूसरों के बीच) कहा जाता है । आप उन सभी को यहां देख सकते हैं
तो आपको जो करने की आवश्यकता है वह एक फ़ंक्शन है जिसे उस समय पारित होने वाले डेटा के साथ किसी बिंदु पर निष्पादित करने का वादा किया जाता है।
क्योंकि एक कॉलबैक तुरंत निष्पादित नहीं किया जाता है, लेकिन बाद में उस फ़ंक्शन के संदर्भ को पारित करना महत्वपूर्ण होता है, जिसे निष्पादित नहीं किया गया है। तोह फिर
function foo(bla) {
console.log(bla)
}
तो ज्यादातर समय (लेकिन हमेशा नहीं) आप पास foo
नहीं होंगेfoo()
उम्मीद है कि कुछ समझ में आएगा। जब आप इस तरह की चीजों का सामना करते हैं जो भ्रामक लगती हैं - तो मैं बहुत कम से कम इसकी समझ पाने के लिए प्रलेखन को पूरी तरह से पढ़ने की सलाह देता हूं। यह आपको बहुत बेहतर डेवलपर बना देगा।