Hoe retourneer ik het antwoord van een asynchrone oproep?

Ik heb een functie foo die een Ajax verzoek doet. Hoe kan ik het antwoord van foo teruggeven?

Ik heb geprobeerd om de waarde van de success callback terug te geven, maar ook om het antwoord toe te wijzen aan een lokale variabele in de functie en die terug te geven, maar geen van deze manieren geeft daadwerkelijk het antwoord terug.

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;
}

var result = foo(); // It always ends up being `undefined`.
Oplossing

→ Voor een meer algemene uitleg van async gedrag met verschillende voorbeelden, zie https://stackoverflow.com/q/23667086/218196

→ Als u het probleem al begrijpt, ga dan naar de mogelijke oplossingen hieronder.

Het probleem

De A in Ajax staat voor asynchroon . Dat betekent dat het versturen van het verzoek (of beter gezegd het ontvangen van het antwoord) uit de normale uitvoeringsstroom wordt gehaald. In jouw voorbeeld komt $.ajax onmiddellijk terug en het volgende statement, return result;, wordt uitgevoerd voordat de functie die je als success callback hebt doorgegeven zelfs maar is aangeroepen. Hier is een analogie die hopelijk het verschil tussen synchrone en asynchrone flow duidelijker maakt:

Synchroon

Stel je voor dat je een telefoontje pleegt naar een vriend en hem vraagt iets voor je op te zoeken. Hoewel het even kan duren, wacht je aan de telefoon en staar je in de ruimte, totdat je vriend je het antwoord geeft dat je nodig had. Hetzelfde gebeurt wanneer je een functie aanroept die "normale" code bevat:

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

Ook al duurt findItem lang om uit te voeren, alle code die na var item = findItem(); komt, moet wachten totdat de functie het resultaat teruggeeft.

Asynchroon

Je belt je vriend weer voor dezelfde reden. Maar deze keer vertel je hem dat je haast hebt en dat hij je moet terugbellen op je mobiele telefoon. U hangt op, verlaat het huis en doet wat u van plan was te doen. Zodra uw vriend u terugbelt, bent u bezig met de informatie die hij u gaf. Dat'is precies wat'er gebeurt als je een Ajax verzoek doet.

findItem(function(item) {
    // Do something with item
});
doSomethingElse();

In plaats van te wachten op het antwoord, gaat de uitvoering meteen door en wordt het statement na de Ajax-aanroep uitgevoerd. Om het antwoord uiteindelijk te krijgen, voorzie je een functie die moet worden aangeroepen zodra het antwoord is ontvangen, een callback (merk je iets? callback ?). Elk statement dat na die call komt wordt uitgevoerd voordat de callback wordt aangeroepen.

Solution(s)

**Hoewel bepaalde asynchrone operaties synchrone tegenhangers hebben (zo ook "Ajax"), wordt het over het algemeen afgeraden om ze te gebruiken, vooral in een browser context. Waarom is het slecht vraag je je af? JavaScript draait in de UI thread van de browser en elk lang lopend proces zal de UI blokkeren, waardoor deze niet meer reageert. Bovendien is er een bovengrens aan de uitvoeringstijd voor JavaScript en zal de browser de gebruiker vragen of hij met de uitvoering wil doorgaan of niet. Dit alles is echt een slechte gebruikerservaring. De gebruiker zal niet in staat zijn om te zien of alles goed werkt of niet. Bovendien zal het effect erger zijn voor gebruikers met een trage verbinding. In het volgende zullen we drie verschillende oplossingen bekijken die allemaal op elkaar voortbouwen:

  • Promises met async/await (ES2017+, beschikbaar in oudere browsers als je een transpiler of regenerator gebruikt)
  • Callbacks (populair in node)
  • Beloften met then() (ES2015+, beschikbaar in oudere browsers als je een van de vele belofte bibliotheken gebruikt) Alledrie zijn beschikbaar in de huidige browsers, en in node 7+.

    ES2017+: Beloftes met async/await

    De ECMAScript versie uitgebracht in 2017 introduceerde syntax-level support voor asynchrone functies. Met behulp van async en await kun je asynchroon schrijven in een "synchrone stijl". De code is nog steeds asynchroon, maar het'is makkelijker te lezen/begrijpen. async/await bouwt bovenop beloften: een async functie retourneert altijd een belofte. await "unwraps" een belofte en resulteert ofwel in de waarde waarmee de belofte werd opgelost of gooit een fout als de belofte werd afgewezen. Belangrijk: Je kunt await alleen gebruiken binnen een async functie. Op dit moment wordt top-level await nog niet ondersteund, dus moet je misschien een async IIFE (Immediately Invoked Function Expression) maken om een async context te starten. Je kunt meer lezen over async en await op MDN. Hier is een voorbeeld dat voortbouwt op bovenstaande vertraging:

// 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);
})();

De huidige browser en node versies ondersteunen async/await. Je kunt ook oudere omgevingen ondersteunen door je code om te zetten naar ES5 met behulp van regenerator (of tools die regenerator gebruiken, zoals Babel).

Laat functies callbacks accepteren

Een callback is eenvoudigweg een functie die aan een andere functie wordt doorgegeven. Die andere functie kan de doorgegeven functie aanroepen wanneer het klaar is. In de context van een asynchroon proces zal de callback worden aangeroepen wanneer het asynchroon proces klaar is. Gewoonlijk wordt het resultaat doorgegeven aan de callback. In het voorbeeld van de vraag, kun je foo een callback laten accepteren en deze gebruiken als succes callback. Dus dit

var result = foo();
// Code that depends on 'result'

wordt

foo(function(result) {
    // Code that depends on 'result'
});

Hier hebben we de functie "inline" gedefinieerd, maar je kunt elke functie verwijzing doorgeven:

function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

foo zelf is als volgt gedefinieerd:

function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

callback zal verwijzen naar de functie die we doorgeven aan foo wanneer we deze aanroepen en we geven deze simpelweg door aan success. Dat wil zeggen, zodra het Ajax verzoek succesvol is, zal $.ajax callback aanroepen en het antwoord doorgeven aan de callback (waarnaar verwezen kan worden met result, omdat dit is hoe we de callback gedefinieerd hebben). Je kunt het antwoord ook verwerken voordat je het aan de callback doorgeeft:

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}

Het's makkelijker om code te schrijven met behulp van callbacks dan het misschien lijkt. Immers, JavaScript in de browser is zwaar event-driven (DOM events). Het ontvangen van het Ajax antwoord is niets anders dan een gebeurtenis.
Er kunnen problemen ontstaan wanneer je moet werken met code van derden, maar de meeste problemen kunnen worden opgelost door gewoon de applicatie flow te doordenken.

ES2015+: Beloftes met then()

De Promise API is een nieuwe functie van ECMAScript 6 (ES2015), maar het heeft al goede browser ondersteuning. Er zijn ook veel bibliotheken die de standaard Promises API implementeren en aanvullende methoden bieden om het gebruik en de samenstelling van asynchrone functies te vergemakkelijken (bijv. bluebird). Beloften zijn containers voor toekomstige waarden. Wanneer de belofte de waarde ontvangt (het is opgelost) of wanneer het wordt geannuleerd (afgewezen), informeert het al zijn "listeners" die toegang willen tot deze waarde. Het voordeel ten opzichte van gewone callbacks is dat ze je toelaten je code te ontkoppelen en dat ze gemakkelijker zijn samen te stellen. Hier is een eenvoudig voorbeeld van het gebruik van een belofte:

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

Toegepast op onze Ajax call zouden we beloftes als volgt kunnen gebruiken:

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

Het beschrijven van alle voordelen die promise bieden valt buiten het bestek van dit antwoord, maar als je nieuwe code schrijft, zou je ze serieus moeten overwegen. Ze zorgen voor een grote abstractie en scheiding van je code. Meer informatie over beloften: HTML5 rocks - JavaScript Promises

Kanttekening: jQuery's uitgestelde objecten

Uitgestelde objecten zijn jQuery's aangepaste implementatie van beloften (voordat de belofte-API werd gestandaardiseerd). Ze gedragen zich bijna als promises maar stellen een iets andere API bloot. Elke Ajax methode van jQuery retourneert al een "deferred object" (eigenlijk een belofte van een deferred object) die je gewoon vanuit je functie kunt retourneren:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

Kanttekening: Belofte gotchas

Hou in gedachten dat beloftes en uitgestelde objecten enkel containers zijn voor een toekomstige waarde, ze zijn niet de waarde zelf. Bijvoorbeeld, stel dat je het volgende had:

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
}

Deze code begrijpt de bovenstaande asynchronie problemen niet. Specifiek, $.ajax() bevriest de code niet terwijl het de '/password' pagina op je server controleert - het stuurt een verzoek naar de server en terwijl het wacht, retourneert het onmiddellijk een jQuery Ajax Deferred object, niet het antwoord van de server. Dat betekent dat het if statement altijd dit Deferred object krijgt, het als true behandelt, en verder gaat alsof de gebruiker is ingelogd. Dat is niet goed. Maar de oplossing is eenvoudig:

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

Niet aanbevolen: Synchrone "Ajax" aanroepen

Zoals ik al zei, sommige(!) asynchrone operaties hebben synchrone tegenhangers. Ik ben geen voorstander van het gebruik ervan, maar voor de volledigheid volgt hier hoe je een synchrone oproep zou uitvoeren:

Zonder jQuery

Als je direct een XMLHTTPRequest object gebruikt, geef dan false door als derde argument aan .open.

jQuery

Als je jQuery gebruikt, kun je de async optie op false zetten. Merk op dat deze optie deprecated is sinds jQuery 1.8. Je kunt dan nog steeds een success callback gebruiken of de responseText eigenschap van het jqXHR object benaderen:

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

Als je een andere jQuery Ajax methode gebruikt, zoals $.get, $.getJSON, etc., moet je deze veranderen in $.ajax (omdat je alleen configuratie parameters kunt doorgeven aan $.ajax). **Het is niet mogelijk om een synchroon JSONP verzoek te doen. JSONP is van nature altijd asynchroon (nog een reden om deze optie niet eens te overwegen).

Commentaren (35)

Als je geen jQuery in je code gebruikt, is dit antwoord voor jou.

Je code zou iets in de trant van dit moeten zijn:

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Felix Kling heeft goed werk verricht met het schrijven van een antwoord voor mensen die jQuery gebruiken voor AJAX, ik'heb besloten om een alternatief te bieden voor mensen die'dat niet doen.

(Opmerking, voor degenen die de nieuwe fetch API, Angular of promises gebruiken heb ik'hieronder een ander antwoord toegevoegd)


Wat u're geconfronteerd

Dit is een korte samenvatting van "Uitleg van het probleem" uit het andere antwoord, als je'niet zeker bent na het lezen van dit, lees dat dan.

De A in AJAX staat voor asynchroon. Dat betekent dat het verzenden van het verzoek (of liever het ontvangen van het antwoord) uit de normale uitvoeringsstroom wordt gehaald. In uw voorbeeld, .send keert onmiddellijk terug en het volgende statement, return result;, wordt uitgevoerd voordat de functie die u als success callback doorgaf zelfs maar is aangeroepen.

Dit betekent dat wanneer je'teruggaat, de luisteraar die je'hebt gedefinieerd nog niet is uitgevoerd, wat betekent dat de waarde die je'teruggeeft nog niet is gedefinieerd.

Hier is een eenvoudige analogie

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

[(Fiddle)][2]

De geretourneerde waarde van a is undefined omdat het a=5 gedeelte nog niet is uitgevoerd. AJAX werkt zo, je'retourneert de waarde voordat de server de kans heeft gekregen om je browser te vertellen wat die waarde is.

Een mogelijke oplossing voor dit probleem is om re-actief te coderen, door je programma te vertellen wat het moet doen als de berekening voltooid is.

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

Dit wordt CPS genoemd. In principe geven we getFive een actie door om uit te voeren wanneer het is voltooid, we vertellen onze code hoe te reageren wanneer een gebeurtenis is voltooid (zoals onze AJAX-oproep, of in dit geval de time-out).

Gebruik zou zijn:

getFive(onComplete);

Dat zou "5" op het scherm moeten brengen. [(Fiddle)][4].

Mogelijke oplossingen

Er zijn in principe twee manieren om dit op te lossen:

  1. Maak de AJAX oproep synchroon (laten we het SJAX noemen).
  2. Herstructureer je code om goed te werken met callbacks.

1. Synchrone AJAX - Doe het niet!!!

Wat synchrone AJAX betreft, doe het niet! Felix's antwoord geeft een aantal overtuigende argumenten waarom het'een slecht idee is. Om het samen te vatten, het'zal de browser van de gebruiker bevriezen totdat de server het antwoord terugstuurt en een zeer slechte gebruikerservaring creëren. Hier is nog een korte samenvatting van MDN over waarom:

XMLHttpRequest ondersteunt zowel synchrone als asynchrone communicatie. In het algemeen moeten asynchrone verzoeken echter worden verkozen boven synchrone verzoeken om prestatieredenen.

In het kort, synchrone verzoeken blokkeren de uitvoering van code... ...dit kan serieuze problemen veroorzaken...

Als je het moet doen, kun je een vlag doorgeven: Hier staat hoe:

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. Herstructureer code

Laat je functie een callback accepteren. In de voorbeeldcode kan foo een callback accepteren. We'zullen onze code vertellen hoe te reageren wanneer foo voltooid is.

Dus:

var result = foo();
// code that depends on `result` goes here

Wordt:

foo(function(result) {
    // code that depends on `result`
});

Hier hebben we een anonieme functie doorgegeven, maar we kunnen net zo goed een verwijzing naar een bestaande functie doorgeven, zodat het er zo uitziet:

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

Voor meer details over hoe dit soort callback-ontwerp wordt gedaan, bekijk Felix's antwoord.

Laten we nu foo zelf definiëren om dienovereenkomstig te handelen

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

[(fiddle)][6]

We hebben nu onze foo functie een actie laten accepteren om uit te voeren wanneer de AJAX succesvol is voltooid, we kunnen dit verder uitbreiden door te controleren of de respons status niet 200 is en dienovereenkomstig te handelen (maak een fail handler en dergelijke). Effectief oplossen van ons probleem.

Als je nog steeds moeite hebt om dit te begrijpen lees de AJAX getting started guide op MDN.

Commentaren (4)

XMLHttpRequest 2 (lees eerst de antwoorden van Benjamin Gruenbaum & Felix Kling) Als je geen jQuery gebruikt en een mooie korte XMLHttpRequest 2 wilt die werkt op de moderne browsers en ook op de mobiele browsers stel ik voor om het op deze manier te gebruiken:

function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

Zoals je kan zien:

  1. Het'is korter dan alle andere genoemde functies.
  2. De callback wordt direct gezet (dus geen extra onnodige closures).
  3. Het gebruikt de nieuwe onload (dus je hoeft niet te controleren op readystate && status)
  4. Er zijn nog wat andere situaties die ik me niet meer herinner die de XMLHttpRequest 1 vervelend maken. Er zijn twee manieren om het antwoord van deze Ajax-aanroep te krijgen (drie met behulp van de XMLHttpRequest var naam): De eenvoudigste:
this.response

Of als je om een of andere reden bind() de callback aan een class:

e.target.response

Voorbeeld:

function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

Of (de bovenstaande is beter anonieme functies zijn altijd een probleem):

ajax('URL', function(e){console.log(this.response)});

Niets eenvoudiger. Nu zullen sommige mensen waarschijnlijk zeggen dat het'beter is om onreadystatechange of de zelfs de XMLHttpRequest variabele naam te gebruiken. Dat's verkeerd. Kijk eens naar XMLHttpRequest geavanceerde functies Het ondersteunt alle *moderne browsers. En ik kan het bevestigen aangezien ik'm deze aanpak gebruik sinds XMLHttpRequest 2 bestaat. Ik heb nooit enig type probleem gehad op alle browsers die ik gebruik. onreadystatechange is alleen nuttig als je de headers op state 2 wilt krijgen. Het gebruik van de XMLHttpRequest variabele naam is een andere grote fout omdat je de callback moet uitvoeren binnen de onload/oreadystatechange closures anders ben je het kwijt.

Als je nu iets complexers wilt met post en FormData kun je deze functie eenvoudig uitbreiden:

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

Nogmaals ... het'is een zeer korte functie, maar het krijgt wel & post. Voorbeelden van gebruik:

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

Of geef een volledig formulier-element door (document.getElementsByTagName('form')[0]):

var fd = new FormData(form);
x(url, callback, 'post', fd);

Of stel een aantal aangepaste waarden in:

var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

Zoals je kunt zien heb ik'geen sync geïmplementeerd ... het is een slechte zaak. Dat gezegd hebbende ... waarom doe je het niet op de gemakkelijke manier?

Zoals vermeld in de opmerking breekt het gebruik van fout && synchroon wel volledig het punt van het antwoord. Wat is een mooie korte manier om Ajax op de juiste manier te gebruiken? Error handler

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

In het bovenstaande script heb je een error handler die statisch gedefinieerd is zodat het de functie niet in gevaar brengt. De error handler kan ook voor andere functies gebruikt worden. Maar om echt een foutmelding te krijgen is de enige manier om een verkeerde URL te schrijven in welk geval elke browser een foutmelding geeft. Error handlers zijn misschien nuttig als je custom headers instelt, de responseType instelt op blob array buffer of wat dan ook... Zelfs als je 'POSTAPAP' doorgeeft als de methode zal het geen fout geven. Zelfs als je 'fdggdgilfdghfldj' als formdata doorgeeft zal het geen fout geven. In het eerste geval zit de fout in de displayAjax() onder this.statusText als Method not Allowed. In het tweede geval werkt het gewoon. Je moet aan de server kant controleren of je de juiste post data hebt doorgegeven. cross-domain not allowed gooit automatisch error. In de foutmelding staan geen foutcodes. Er is alleen de this.type die is ingesteld op error. Waarom een error handler toevoegen als je totaal geen controle hebt over fouten? De meeste fouten worden hierbinnen geretourneerd in de callback functie displayAjax(). Dus: Foutcontroles zijn niet nodig als je'de URL goed kunt kopiëren en plakken. ;) PS: Als eerste test schreef ik x('x', displayAjax)..., en het kreeg totaal geen reactie...?? Dus ik controleerde de map waar de HTML zich bevindt, en er was een bestand met de naam 'x.xml'. Dus zelfs als je de extensie van je bestand vergeet, zal XMLHttpRequest 2 het vinden. Ik LOL'd

Leest een bestand synchroon Don't do that. Als je de browser een tijdje wil blokkeren laad dan een mooi groot .txt bestand synchroon.

function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

Nu kun je

 var res = omg('thisIsGonnaBlockThePage.txt');

Er is geen andere manier om dit op een niet-asynchrone manier te doen. (Ja, met setTimeout loop... maar serieus?) Een ander punt is... als je werkt met API's of gewoon je eigen list's files of wat dan ook gebruik je altijd verschillende functies voor elk request... Alleen als je een pagina hebt waar je altijd dezelfde XML/JSON of wat dan ook laadt heb je maar één functie nodig. In dat geval, pas een beetje de Ajax functie aan en vervang b door je speciale functie.

De bovenstaande functies zijn voor basisgebruik. Als je de functie wilt UITBREIDEN... Ja, dat kan. Ik'gebruik veel APIs en een van de eerste functies die ik in elke HTML pagina integreer is de eerste Ajax functie in dit antwoord, met alleen GET... Maar je kunt een heleboel dingen doen met XMLHttpRequest 2: Ik heb een download manager gemaakt (die aan beide kanten reeksen gebruikt met resume, filereader, filesystem), verschillende image resizers converters die canvas gebruiken, web SQL databases vullen met base64images en nog veel meer... Maar in deze gevallen zou je een functie alleen voor dat doel moeten maken... soms heb je een blob nodig, array buffers, je kunt headers instellen, mimetype overschrijven en er is nog veel meer... Maar de vraag hier is hoe je een Ajax antwoord terugstuurt... (Ik heb een makkelijke manier toegevoegd.)

Commentaren (7)