jQuery: Returner data etter vellykket ajax-anrop
Jeg har noe sånt som dette, der det er et enkelt kall til et skript som gir meg tilbake en verdi, en streng...
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
men hvis jeg kaller noe som dette
var output = testAjax(svar); // output will be undefined...
så hvordan kan jeg returnere verdien? koden nedenfor ser ikke ut til å fungere heller ...
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
}
});
return data;
}
444
3
**Merk: Dette svaret ble skrevet i februar 2010. Se oppdateringer fra 2015, 2016 og 2017 nederst. Du kan ikke returnere noe fra en funksjon som er asynkron. Det du kan returnere er et løfte*. Jeg forklarte hvordan løfter fungerer i jQuery i svarene mine på disse spørsmålene:
kan du skrive testAjax-funksjonen din slik:
Da kan du få løftet ditt slik:
Du kan lagre løftet ditt, du kan sende det rundt, du kan bruke det som et argument i funksjonskall og du kan returnere det fra funksjoner, men når du til slutt vil bruke dataene dine som returneres av AJAX-kallet, må du gjøre det slik:
(Se oppdateringer nedenfor for forenklet syntaks.). Hvis dataene dine er tilgjengelige på dette tidspunktet, vil denne funksjonen påkalles umiddelbart. Hvis den ikke er det, vil den bli påkalt så snart dataene er tilgjengelige. Hele poenget med å gjøre alt dette er at dataene dine ikke er tilgjengelige umiddelbart etter kallet til $.ajax fordi det er asynkront. Løfter er en fin abstraksjon for funksjoner å si: Jeg kan ikke returnere dataene fordi jeg ikke har dem ennå, og jeg vil ikke blokkere og få deg til å vente, så her er et løfte i stedet, og du vil kunne bruke det senere, eller bare gi det til noen andre og være ferdig med det. Se denne [DEMO](http://jsfiddle.net/jW68r/). OPPDATERING (2015)
For øyeblikket (per mars 2015) er jQuery Promises ikke kompatibelt med Promises/A+-spesifikasjonen, noe som betyr at de kanskje ikke samarbeider særlig godt med andre Promises/A+-konforme implementeringer. Men jQuery Promises i den kommende versjonen 3.x vil være kompatibel med Promises/A+-spesifikasjonen (takk til Benjamin Gruenbaum for å ha påpekt det). For øyeblikket (per mai 2015) er de stabile versjonene av jQuery 1.x og 2.x.
Det jeg forklarte ovenfor (i mars 2011) er en måte å bruke jQuery Deferred Objects for å gjøre noe asynkront som i synkron kode ville oppnås ved å returnere en verdi. Men et synkront funksjonskall kan gjøre to ting - det kan enten returnere en verdi (hvis det kan) eller kaste et unntak (hvis det ikke kan returnere en verdi). Løfter / A + adresserer begge disse brukstilfellene på en måte som er ganske mye så kraftig som unntakshåndtering i synkron kode. JQuery-versjonen håndterer ekvivalenten til å returnere en verdi helt fint, men ekvivalenten til kompleks unntakshåndtering er noe problematisk. Spesielt er hele poenget med unntakshåndtering i synkron kode ikke bare å gi opp med en fin melding, men å prøve å løse problemet og fortsette kjøringen, eller muligens kaste det samme eller et annet unntak for noen andre deler av programmet å håndtere. I synkron kode har du en anropsstabel. I asynkron samtale har du ikke det, og avansert unntakshåndtering inne i løftene dine som kreves av Promises / A + -spesifikasjonen kan virkelig hjelpe deg med å skrive kode som vil håndtere feil og unntak på en meningsfull måte, selv for komplekse brukstilfeller. For forskjeller mellom jQuery og andre implementeringer, og hvordan du konverterer jQuery-løfter til Promises/A+-kompatible, se Coming from jQuery av Kris Kowal et al. på Q-bibliotekets wiki og Promises arrive in JavaScript av Jake Archibald på HTML5 Rocks.
Hvordan returnere et ekte løfte
Funksjonen fra mitt eksempel ovenfor:
returnerer et jqXHR-objekt, som er et jQuery Deferred Object. For å få det til å returnere et ekte løfte, kan du endre det til - ved hjelp av metoden fra Q wiki:
eller ved å bruke metoden fra HTML5 Rocks-artikkelen:
Denne
Promise.resolve($.ajax(...))
er også forklart i dokumentasjonen forpromise
-modulen, og den skal fungere med ES6Promise.resolve()
. For å bruke ES6 Promises i dag kan du bruke es6-promise-modulenspolyfill()
av Jake Archibald. For å se hvor du kan bruke ES6 Promises uten polyfill, se: Kan jeg bruke: Promises. For mer informasjon, se:Fremtiden til jQuery
Fremtidige versjoner av jQuery (fra og med 3.x - nåværende stabile versjoner per mai 2015 er 1.x og 2.x) vil være kompatible med Promises/A+-spesifikasjonen (takk til Benjamin Gruenbaum for å påpeke det i kommentarene). "To endringer som vi allerede har bestemt oss for er Promise/A+-kompatibilitet for vår utsatte implementering [...]" (jQuery 3.0 og fremtiden for webutvikling). For mer informasjon, se: jQuery 3.0: The Next Generations av Dave Methvin og jQuery 3.0: More interoperability, less Internet Explorer av Paul Krill.
Interessante foredrag
[JavaScript Promises](https://youtu.be/oa2clhsYIDY) av David M. Lee (Nodevember 2014) OPPDATERING (2016)
Det finnes en ny syntaks i ECMA-262, 6th Edition, Section 14.2 kalt arrow functions som kan brukes til å forenkle eksemplene ovenfor ytterligere. Bruk av jQuery API, i stedet for:
kan du skrive:
eller bruke Promises/A+ API:
Husk å alltid bruke rejection handlers enten med:
eller med:
Se dette svaret for å se hvorfor du alltid bør bruke rejection handlers med promises:
promise.then(alert)
fordi du bare kalleralert
med de samme argumentene som tilbakeringingen din, men pil-syntaksen er mer generell og lar deg skrive ting som:Ikke alle nettlesere støtter denne syntaksen ennå, men det er visse tilfeller der du er sikker på hvilken nettleser koden din vil kjøre på - f.eks. når du skriver en Chrome-utvidelse, et Firefox-tillegg eller en skrivebordsapplikasjon som bruker Electron, NW.js eller AppJS (se dette svaret for detaljer). For støtte for pilfunksjoner, se:
await
nøkkelord som i stedet for denne koden:lar deg skrive:
Du kan bare bruke det inne i en funksjon som er opprettet med nøkkelordet
async
. For mer informasjon, se:async
ogawait
kan du bruke Babel:co
eller Bluebird coroutines:http://bluebirdjs.com/docs/api/promise.coroutine.html Mer info
Noen andre spørsmål om løfter for mer informasjon:
Den eneste måten å returnere dataene fra funksjonen ville være å foreta et synkront kall i stedet for et asynkront kall, men det ville fryse nettleseren mens den venter på svaret.
Du kan sende inn en tilbakeringingsfunksjon som håndterer resultatet:
Kall den slik:
Se eksempel på jquery-dokumenter: http://api.jquery.com/jQuery.ajax/ (ca. 2/3 av siden)
Du leter kanskje etter følgende kode:
Samme side...lenger ned.