J'ai une fonction foo qui fait une requête Ajax. Comment puis-je retourner la réponse de foo?

J'ai essayé de renvoyer la valeur du rappel success ainsi que d'attribuer la réponse à une variable locale à l'intérieur de la fonction et de renvoyer celle-ci, mais aucune de ces façons ne retourne réellement la réponse.

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`.
5383
Felix Kling 8 janv. 2013 à 21:06

11 réponses

Vous utilisez Ajax de manière incorrecte. L'idée n'est pas de lui renvoyer quoi que ce soit, mais de transmettre les données à quelque chose appelé une fonction de rappel, qui gère les données.

C'est:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

Renvoyer quoi que ce soit dans le gestionnaire de soumission ne fera rien. Vous devez au lieu de cela remettre les données ou faire ce que vous voulez directement avec elles dans la fonction de réussite.

238
Peter Mortensen 21 nov. 2015 à 14:07

En bref, vous devez implémenter un rappel comme celui-ci:

function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});
78
Pablo Matias Gomez 9 août 2016 à 18:32

Je répondrai avec une bande dessinée à la main horrible. La deuxième image est la raison pour laquelle result est undefined dans votre exemple de code.

enter image description here

208
Johannes Fahrenkrug 11 août 2016 à 17:12

C'est l'un des endroits où la liaison bidirectionnelle des données ou le concept de magasin utilisé dans de nombreux nouveaux frameworks JavaScript fonctionnera très bien pour vous ...

Donc, si vous utilisez Angular, React ou tout autre framework qui fait une liaison de données bidirectionnelle ou concept de magasin , ce problème est simplement résolu pour vous, donc en un mot, votre résultat est undefined à la première étape, donc vous avez result = undefined avant de recevoir les données, puis dès que vous obtenez le résultat, il sera mis à jour et affecté à la nouvelle valeur de la réponse de votre appel Ajax ...

Mais comment pouvez-vous le faire en javascript pur ou en jQuery par exemple comme vous l'avez demandé dans cette question?

Vous pouvez utiliser un rappel , une promesse et récemment observable pour le gérer pour vous, par exemple dans les promesses, nous avons une fonction comme {{X0} } ou then() qui seront exécutés lorsque vos données seront prêtes pour vous, de même avec le rappel ou la fonction s'abonner sur observable .

Par exemple, dans votre cas que vous utilisez jQuery , vous pouvez faire quelque chose comme ceci:

$(document).ready(function(){
    function foo() {
        $.ajax({url: "api/data", success: function(data){
            fooDone(data); //after we have data, we pass it to fooDone
        }});
    };

    function fooDone(data) {
        console.log(data); //fooDone has the data and console.log it
    };

    foo(); //call happens here
});

Pour plus d'informations, étudiez les promesses et les observables qui sont des moyens plus récents de faire ces trucs asynchrones.

96
Alireza 23 sept. 2019 à 03:14

Jetez un œil à cet exemple:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

Comme vous pouvez le voir, getJoke renvoie une promesse résolue (elle est résolue lors du retour de res.data.value). Vous attendez donc jusqu'à ce que la demande $ http.get soit terminée, puis console.log (res.joke) est exécuté (comme un flux asynchrone normal).

Voici le plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

manière ES6 (async - attendre)

(function(){
  async function getJoke(){
    let response = await fetch('http://api.icndb.com/jokes/random');
    let data = await response.json();
    return data.value;
  }

  getJoke().then((joke) => {
    console.log(joke);
  });
})();
104
Francisco Carmona 23 nov. 2018 à 12:19

Bien sûr, il existe de nombreuses approches comme la demande synchrone, promis, mais d'après mon expérience, je pense que vous devriez utiliser l'approche de rappel. C'est naturel au comportement asynchrone de Javascript. Ainsi, votre extrait de code peut être réécrit un peu différemment:

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            myCallback(response);
        }
    });

    return result;
}

function myCallback(response) {
    // Does something.
}
28
Michał Perłakowski 7 mars 2018 à 14:23

La solution la plus simple consiste à créer une fonction JavaScript et à l'appeler pour le rappel Ajax success.

function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 
225
clearlight 15 janv. 2017 à 06:17

Utilisez une fonction callback() dans le succès foo(). Essayez de cette façon. C'est simple et facile à comprendre.

var lat = "";
var lon = "";
function callback(data) {
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();
35
Alex Weitz 17 nov. 2017 à 09:15

Vous pouvez utiliser cette bibliothèque personnalisée (écrite à l'aide de Promise) pour effectuer un appel à distance.

function $http(apiConfig) {
    return new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open(apiConfig.method, apiConfig.url);
        client.send();
        client.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                // Performs the function "resolve" when this.status is equal to 2xx.
                // Your logic here.
                resolve(this.response);
            }
            else {
                // Performs the function "reject" when this.status is different than 2xx.
                reject(this.statusText);
            }
        };
        client.onerror = function () {
            reject(this.statusText);
        };
    });
}

Exemple d'utilisation simple:

$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});
65
Peter Mortensen 17 déc. 2016 à 10:59

En utilisant ES2017, vous devriez avoir ceci comme déclaration de fonction

async function foo() {
    var response = await $.ajax({url: '...'})
    return response;
}

Et l'exécuter comme ça.

(async function() {
    try {
        var result = await foo()
        console.log(result)
    } catch (e) {}
})()

Ou la syntaxe Promise

foo().then(response => {
    console.log(response)

}).catch(error => {
    console.log(error)

})
16
Fernando Carvajal 24 janv. 2018 à 06:18

Une autre approche pour renvoyer une valeur à partir d'une fonction asynchrone consiste à passer un objet qui stockera le résultat de la fonction asynchrone.

Voici un exemple de la même:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

J'utilise l'objet result pour stocker la valeur pendant l'opération asynchrone. Cela permet au résultat d'être disponible même après le travail asynchrone.

J'utilise beaucoup cette approche. Je serais intéressé de savoir à quel point cette approche fonctionne bien lorsque le câblage du résultat via des modules consécutifs est impliqué.

92
Peter Mortensen 17 déc. 2016 à 12:55