jQuery: Return data efter ajax-opkald succes
Jeg har noget som dette, hvor det er et simpelt kald til et script, der giver mig en værdi tilbage, en streng...
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
men hvis jeg kalder noget som dette
var output = testAjax(svar); // output will be undefined...
så hvordan kan jeg returnere værdien? nedenstående kode ser heller ikke ud til at virke...
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
}
});
return data;
}
444
3
Bemærk: Dette svar blev skrevet i februar 2010.
Se opdateringer fra 2015, 2016 og 2017 nederst. Du kan ikke returnere noget fra en funktion, der er asynkron. Det, du kan returnere, er et løfte. Jeg forklarede, hvordan promises fungerer i jQuery i mine svar på disse spørgsmål:
kan du skrive din testAjax-funktion sådan her:
Så kan du få dit løfte på denne måde:
Du kan gemme dit løfte, du kan sende det rundt, du kan bruge det som et argument i funktionsopkald og du kan returnere det fra funktioner, men når du endelig vil bruge dine data, der returneres af AJAX-opkaldet, skal du gøre det sådan her:
(Se opdateringer nedenfor for forenklet syntaks.) Hvis dine data er tilgængelige på dette tidspunkt, vil denne funktion blive påberåbt med det samme. Hvis den ikke er det, vil den blive påberåbt, så snart dataene er tilgængelige. Hele pointen med at gøre alt dette er, at dine data ikke er tilgængelige umiddelbart efter opkaldet til $.ajax, fordi det er asynkront. Promises er en dejlig abstraktion for funktioner til at sige: Jeg kan ikke returnere dataene til dig, fordi jeg ikke har dem endnu, og jeg vil ikke blokere og lade dig vente, så her er et løfte i stedet, så du kan bruge dem senere, eller bare give dem til en anden og være færdig med dem. Se denne [DEMO](http://jsfiddle.net/jW68r/). UPDATE (2015)
I øjeblikket (fra marts 2015) er jQuery Promises ikke kompatible med Promises/A+-specifikationen, hvilket betyder, at de muligvis ikke samarbejder særlig godt med andre Promises/A+-konforme implementeringer. Men jQuery Promises i den kommende version 3.x vil være kompatible med Promises/A+-specifikationen (tak til Benjamin Gruenbaum for at gøre opmærksom på det). I øjeblikket (fra maj 2015) er de stabile versioner af jQuery 1.x og 2.x.
Det, jeg forklarede ovenfor (i marts 2011), er en måde at bruge jQuery Deferred Objects til at gøre noget asynkront, som i synkron kode ville blive opnået ved at returnere en værdi. Men et synkront funktionskald kan gøre to ting - det kan enten returnere en værdi (hvis det kan) eller kaste en undtagelse (hvis det ikke kan returnere en værdi). Promises/A+ tager begge disse anvendelsestilfælde op på en måde, der er stort set lige så effektiv som undtagelseshåndtering i synkron kode. JQuery-versionen håndterer det tilsvarende med at returnere en værdi fint, men det tilsvarende med kompleks undtagelseshåndtering er noget problematisk. Især er hele pointen med undtagelseshåndtering i synkron kode ikke bare at give op med en pæn besked, men at forsøge at løse problemet og fortsætte eksekveringen, eller eventuelt at genkaste den samme eller en anden undtagelse, så andre dele af programmet kan håndtere den. I synkron kode har man en call stack. I asynkrone kald har man ikke det, og avanceret undtagelseshåndtering inden for dine promises som krævet i Promises/A+-specifikationen kan virkelig hjælpe dig med at skrive kode, der håndterer fejl og undtagelser på en meningsfuld måde, selv i komplekse brugssituationer. For forskelle mellem jQuery og andre implementeringer, og hvordan man konverterer jQuery-promiser til Promises/A+-kompatible, se Coming from jQuery af Kris Kowal et al. på Q-bibliotekets wiki og Promises arrive in JavaScript af Jake Archibald på HTML5 Rocks.
Sådan returnerer du et rigtigt løfte
Funktionen fra mit eksempel ovenfor:
returnerer et jqXHR-objekt, som er et jQuery Deferred Object. For at få den til at returnere et rigtigt løfte, kan du ændre det til - ved hjælp af metoden fra Q-wikien:
eller ved hjælp af metoden fra HTML5 Rocks-artiklen:
Denne
Promise.resolve($.ajax(...))
er også det, der er forklaret ipromise
-modulets dokumentation, og det burde fungere med ES6Promise.resolve()
. For at bruge ES6 Promises i dag kan du bruge es6-promise module'spolyfill()
af Jake Archibald. For at se hvor du kan bruge ES6 Promises uden polyfill, se: Can I use: Promises. For yderligere oplysninger se:Fremtiden for jQuery
Fremtidige versioner af jQuery (fra og med 3.x - de nuværende stabile versioner fra maj 2015 er 1.x og 2.x) vil være kompatible med Promises/A+-specifikationen (tak til Benjamin Gruenbaum for at gøre opmærksom på det i kommentarerne). "To ændringer, som vi allerede har besluttet, er Promise/A+-kompatibilitet for vores Deferred-implementering [...]" (jQuery 3.0 and the future of Web development)). For mere information se: jQuery 3.0: The Next Generations af Dave Methvin og jQuery 3.0: More interoperability, less Internet Explorer af Paul Krill.
Interessante foredrag
[JavaScript Promises](https://youtu.be/oa2clhsYIDY) af David M. Lee (Nodevember 2014) UPDATE (2016)
Der findes en ny syntaks i ECMA-262, 6th Edition, Section 14.2 kaldet arrow functions, som kan bruges til at forenkle ovenstående eksempler yderligere. Ved brug af jQuery API'et kan man i stedet for:
kan du skrive:
eller ved hjælp af Promises/A+ API'et:
Husk at du altid skal bruge afvisningshåndteringsprogrammer enten med:
eller med:
Se dette svar for at se, hvorfor du altid skal bruge afvisningshåndteringsprogrammer med løfter:
promise.then(alert)
, fordi du'bare kalderalert
med de samme argumenter som din callback, men pilesyntaksen er mere generel og lader dig skrive ting som f.eks:Ikke alle browsere understøtter denne syntaks endnu, men der er visse tilfælde, hvor du er sikker på, hvilken browser din kode skal køre i - f.eks. når du skriver en Chrome-udvidelse, en Firefox-udvidelse eller en desktop-applikation ved hjælp af Electron, NW.js eller AppJS (se dette svar for nærmere oplysninger). For understøttelse af pilefunktioner, se:
await
, der i stedet for denne kode:lader dig skrive:
Du kan kun bruge det inden for en funktion oprettet med nøgleordet
async
. For mere information, se:async
ogawait
kan du bruge Babel:co
eller Bluebird coroutines:http://bluebirdjs.com/docs/api/promise.coroutine.html Mere info
Nogle andre spørgsmål om promises for flere detaljer:
Den eneste måde at returnere dataene fra funktionen på ville være at foretage et synkront opkald i stedet for et asynkront opkald, men det ville fastfryse browseren, mens den venter på svaret.
Du kan indsætte en callback-funktion, der håndterer resultatet:
Kald den sådan her:
Se jquery docs eksempel: http://api.jquery.com/jQuery.ajax/ (ca. 2/3 af siden)
Du leder måske efter følgende kode:
Samme side...længere nede.