Ik heb zoiets als dit, waar het een simpele oproep is naar een script dat me een waarde teruggeeft, een string...
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
maar als ik zoiets als dit oproep
var output = testAjax(svar); // output will be undefined...
hoe kan ik dan de waarde teruggeven? de onderstaande code lijkt ook niet te werken...
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
}
});
return data;
}
Note: Dit antwoord is geschreven in februari 2010.
Zie updates van 2015, 2016 en 2017 onderaan.
Je kunt'niets retourneren van een functie die asynchroon is. Wat je wel kunt retourneren is een belofte. Hoe promises werken in jQuery heb ik uitgelegd in mijn antwoorden op die vragen:
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
kan je je testAjax functie als volgt schrijven:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
Dan kun je je belofte als volgt krijgen:
var promise = testAjax();
Je kunt je belofte opslaan, je kunt het doorgeven, je kunt het gebruiken als argument in functie-aanroepen en je kunt het retourneren uit functies, maar wanneer je uiteindelijk je gegevens wilt gebruiken die door de AJAX-aanroep zijn geretourneerd, moet je het als volgt doen:
promise.success(function (data) {
alert(data);
});
Op dit moment (vanaf maart, 2015) zijn jQuery Promises niet compatibel met de Promises/A+ specificatie, wat betekent dat ze mogelijk niet goed samenwerken met andere Promises/A+ conforme implementaties. Maar jQuery Promises in de aankomende versie 3.x zal compatibel zijn met de Promises/A+ specificatie (met dank aan Benjamin Gruenbaum voor het erop wijzen). Momenteel (vanaf mei, 2015) zijn de stabiele versies van jQuery 1.x en 2.x.
Wat ik hierboven heb uitgelegd (in maart 2011) is een manier om jQuery Deferred Objects te gebruiken om iets asynchroon te doen dat in synchrone code zou worden bereikt door een waarde terug te geven. Maar een synchrone functie-oproep kan twee dingen doen - het kan ofwel een waarde teruggeven (als het kan) of een uitzondering werpen (als het geen waarde kan teruggeven). Promises/A+ behandelt beide gebruikssituaties op een manier die vrijwel even krachtig is als exception handling in synchrone code. De jQuery versie behandelt het equivalent van het retourneren van een waarde prima, maar het equivalent van complexe uitzondering afhandeling is enigszins problematisch. In het bijzonder, het hele punt van uitzondering behandeling in synchrone code is niet gewoon opgeven met een mooie boodschap, maar proberen om het probleem op te lossen en de uitvoering voort te zetten, of eventueel rethrowing dezelfde of een andere uitzondering voor sommige andere delen van het programma te hanteren. In synchrone code heb je een call stack. In asynchrone aanroep heb je dat niet en geavanceerde exception handling binnen je promises zoals vereist door de Promises/A+ specificatie kan je echt helpen code te schrijven die fouten en excepties op een zinvolle manier zal afhandelen, zelfs voor complexe use cases. Voor verschillen tussen jQuery en andere implementaties, en hoe je jQuery-beloften kunt converteren naar Promises/A+ compliant, zie Coming from jQuery door Kris Kowal et al. op de Q library wiki en Promises komen in JavaScript door Jake Archibald op HTML5 Rocks.
De functie uit mijn voorbeeld hierboven:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
retourneert een jqXHR object, wat een jQuery Deferred Object is. Om het een echte belofte te laten teruggeven, kun je het veranderen in - met behulp van de methode uit de Q wiki:
function testAjax() {
return Q($.ajax({
url: "getvalue.php"
}));
}
of, met de methode uit het HTML5 Rocks artikel:
function testAjax() {
return Promise.resolve($.ajax({
url: "getvalue.php"
}));
}
Deze Promise.resolve($.ajax(...))
is ook wat uitgelegd in de promise
module documentatie en het zou moeten werken met ES6 Promise.resolve()
.
Om de ES6 beloftes vandaag te gebruiken kun je es6-promise module's polyfill()
van Jake Archibald gebruiken.
Om te zien waar je de ES6 Promises kunt gebruiken zonder de polyfill, zie: Kan ik: Promises gebruiken.
Voor meer info zie:
Toekomstige versies van jQuery (vanaf 3.x - huidige stabiele versies vanaf mei 2015 zijn 1.x en 2.x) zullen compatibel zijn met de Promises/A+ specificatie (met dank aan Benjamin Gruenbaum voor het erop wijzen in de comments). "Twee veranderingen die we'al hebben besloten zijn Promise/A+ compatibiliteit voor onze Deferred implementatie [...]" (jQuery 3.0 and the future of Web development). Voor meer info zie: jQuery 3.0: The Next Generations door Dave Methvin en jQuery 3.0: More interoperability, less Internet Explorer door Paul Krill.
Er is een nieuwe syntaxis in ECMA-262, 6th Edition, Section 14.2 genaamd arrow functions die kan worden gebruikt om de bovenstaande voorbeelden verder te vereenvoudigen. Met behulp van de jQuery API, in plaats van:
promise.success(function (data) {
alert(data);
});
kunt u schrijven:
promise.success(data => alert(data));
of met behulp van de Promises/A+ API:
promise.then(data => alert(data));
Vergeet niet om altijd afwijzingshandlers te gebruiken, hetzij met:
promise.then(data => alert(data), error => alert(error));
of met:
promise.then(data => alert(data)).catch(error => alert(error));
Zie dit antwoord om te zien waarom u afwijzingshandlers altijd moet gebruiken met beloften:
promise.then(alert)
kunnen gebruiken omdat je alert
gewoon aanroept met dezelfde argumenten als je callback, maar de pijlensyntaxis is algemener en laat je dingen schrijven als:promise.then(data => alert("x is " + data.x));
Niet elke browser ondersteunt deze syntaxis nog, maar er zijn bepaalde gevallen waarin u'zeker weet op welke browser uw code zal draaien - bijvoorbeeld bij het schrijven van een Chrome-extensie, een Firefox Add-on, of een desktop-applicatie met Electron, NW.js of AppJS (zie dit antwoord voor details). Voor de ondersteuning van pijlfuncties, zie:
await
keyword dat in plaats van deze code:functionReturningPromise()
.then(data => console.log('Data:', data))
.catch(error => console.log('Error:', error));
laat je schrijven:
try {
let data = await functionReturningPromise();
console.log('Data:', data);
} catch (error) {
console.log('Error:', error);
}
Je kunt het alleen gebruiken binnen een functie die gemaakt is met het async
sleutelwoord. Voor meer info, zie:
async
en await
kun je Babel gebruiken:co
of Bluebird coroutines:Enkele andere vragen over promises voor meer details:
De enige manier om de gegevens van de functie terug te sturen zou zijn om een synchrone oproep te doen in plaats van een asynchrone oproep, maar dat zou de browser bevriezen terwijl hij op het antwoord wacht's.
U kunt een callback-functie doorgeven die het resultaat afhandelt:
function testAjax(handleData) {
$.ajax({
url:"getvalue.php",
success:function(data) {
handleData(data);
}
});
}
Roep het als volgt aan:
testAjax(function(output){
// here you use the output
});
// Note: the call won't wait for the result,
// so it will continue with the code here while waiting.
Zie jquery docs voorbeeld: http://api.jquery.com/jQuery.ajax/ (ongeveer 2/3 van de pagina)
Je bent misschien op zoek naar de volgende code:
$.ajax({
url: 'ajax/test.html',
success: function(data) {
$('.result').html(data);
alert('Load was performed.');
}
});
Zelfde pagina...lager.