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

**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:

function testAjax() {
  $.ajax({
    url: "getvalue.php",  
    success: function(data) {
      return data; 
    }
  });
}

kan du skrive testAjax-funksjonen din slik:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

Da kan du få løftet ditt slik:

var promise = testAjax();

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:

promise.success(function (data) {
  alert(data);
});

(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:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

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:

function testAjax() {
  return Q($.ajax({
      url: "getvalue.php"
  }));
}

eller ved å bruke metoden fra HTML5 Rocks-artikkelen:

function testAjax() {
  return Promise.resolve($.ajax({
      url: "getvalue.php"
  }));
}

Denne Promise.resolve($.ajax(...)) er også forklart i dokumentasjonen for promise-modulen, og den skal fungere med ES6 Promise.resolve(). For å bruke ES6 Promises i dag kan du bruke es6-promise-modulens polyfill() av Jake Archibald. For å se hvor du kan bruke ES6 Promises uten polyfill, se: Kan jeg bruke: Promises. For mer informasjon, se:

promise.success(function (data) {
  alert(data);
});

kan du skrive:

promise.success(data => alert(data));

eller bruke Promises/A+ API:

promise.then(data => alert(data));

Husk å alltid bruke rejection handlers enten med:

promise.then(data => alert(data), error => alert(error));

eller med:

promise.then(data => alert(data)).catch(error => alert(error));

Se dette svaret for å se hvorfor du alltid bør bruke rejection handlers med promises:

promise.then(data => alert("x is " + data.x));

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:

  • Det er en enda nyere syntaks akkurat nå kalt async-funksjoner med et nytt await nøkkelord som i stedet for denne koden:
functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

lar deg skrive:

try {
    let data = await functionReturningPromise();
    console.log('Data:', data);
} catch (error) {
    console.log('Error:', error);
}

Du kan bare bruke det inne i en funksjon som er opprettet med nøkkelordet async. For mer informasjon, se:

Kommentarer (9)
Løsning

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:

function testAjax(handleData) {
  $.ajax({
    url:"getvalue.php",  
    success:function(data) {
      handleData(data); 
    }
  });
}

Kall den slik:

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.
Kommentarer (7)

Se eksempel på jquery-dokumenter: http://api.jquery.com/jQuery.ajax/ (ca. 2/3 av siden)

Du leter kanskje etter følgende kode:

    $.ajax({
     url: 'ajax/test.html',
     success: function(data) {
     $('.result').html(data);
     alert('Load was performed.');
   }
});

Samme side...lenger ned.

Kommentarer (0)