Mam funkcję foo, która wysyła żądanie Ajax. Jak mogę zwrócić odpowiedź od foo?

Próbowałem zwrócić wartość z wywołania zwrotnego success, a także przypisać odpowiedź do zmiennej lokalnej wewnątrz funkcji i zwrócić tę, ale żaden z tych sposobów nie zwraca odpowiedzi.

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`.
5787
Felix Kling 8 styczeń 2013, 21:06

12 odpowiedzi

Używając ES2017, powinieneś mieć to jako deklarację funkcji

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

I wykonując to w ten sposób.

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

Albo składnia Promise

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

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

})
16
Fernando Carvajal 24 styczeń 2018, 06:18

Krótka odpowiedź brzmi: musisz zaimplementować takie wywołanie zwrotne:

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

$.ajax({
    url: "...",
    success: callback
});
85
Pablo Matias Gomez 9 sierpień 2016, 18:32

Niepoprawnie używasz Ajax. Chodzi o to, aby nie zwracał niczego, ale zamiast tego przekazał dane do czegoś, co nazywa się funkcją zwrotną, która obsługuje dane.

To jest:

function handleData( responseData ) {

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

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

Zwrócenie czegokolwiek w module obsługi przesyłania nic nie da. Zamiast tego musisz albo przekazać dane, albo zrobić z nimi, co chcesz, bezpośrednio w funkcji sukcesu.

256
Peter Mortensen 21 listopad 2015, 14:07

Najprostszym rozwiązaniem jest utworzenie funkcji JavaScript i wywołanie jej dla wywołania zwrotnego 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);    
}); 
243
clearlight 15 styczeń 2017, 06:17

Odpowiem okropnie wyglądającym, ręcznie rysowanym komiksem. Drugi obraz jest powodem, dla którego w przykładowym kodzie result to undefined.

enter image description here

233
Johannes Fahrenkrug 11 sierpień 2016, 17:12

Spójrz na ten przykład:

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

Jak widać, getJoke zwraca rozwiązaną obietnicę (rozwiązuje się ją przy zwracaniu res.data.value). Dlatego czekasz, aż żądanie $ http.get zostanie zakończone, a następnie zostanie wykonany console.log (res.joke) (jak normalny przepływ asynchroniczny).

To jest plnkr:

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

Sposób ES6 (async - czekaj)

(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);
  });
})();
113
Francisco Carmona 23 listopad 2018, 12:19

Jest to jedno z miejsc, w których dwa sposoby wiązania danych lub koncepcja przechowywania używane w wielu nowych frameworkach JavaScript sprawdzą się doskonale ...

Jeśli więc używasz Angular, React lub innych frameworków, które obsługują dwukierunkowe wiązanie danych lub koncepcję przechowywania , ten problem został po prostu rozwiązany, więc w prostych słowach Twój wynik to undefined na pierwszym etapie, więc masz result = undefined przed otrzymaniem danych, a gdy tylko otrzymasz wynik, zostanie on zaktualizowany i zostanie przypisany do nowa wartość, która jest odpowiedzią na twoje połączenie Ajax ...

Ale jak możesz to zrobić w czystym javascript lub jQuery , na przykład tak jak zadałeś to pytanie?

Możesz użyć wywołania zwrotnego , obietnicy i ostatnio obserwowalnych , aby obsłużyć to za Ciebie, na przykład w obietnicach mamy funkcję, taką jak {{X0} } lub then(), które zostaną wykonane, gdy dane będą gotowe, tak samo jak funkcja wywołania zwrotnego lub subskrypcji na obserwowalne .

Na przykład w Twoim przypadku, w którym używasz jQuery , możesz zrobić coś takiego:

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

Aby uzyskać więcej informacji, zapoznaj się z obietnicami i obserwowalnymi , które są nowszymi sposobami wykonywania tych czynności asynchronicznych.

112
Alireza 23 wrzesień 2019, 03:14

Innym podejściem do zwrócenia wartości z funkcji asynchronicznej jest przekazanie obiektu, który będzie przechowywał wynik funkcji asynchronicznej.

Oto przykład tego samego:

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

Używam obiektu result do przechowywania wartości podczas operacji asynchronicznej. Dzięki temu wynik będzie dostępny nawet po wykonaniu zadania asynchronicznego.

Często używam tego podejścia. Chciałbym wiedzieć, jak dobrze działa to podejście, gdy wymagane jest okablowanie wyniku z powrotem przez kolejne moduły.

101
Peter Mortensen 17 grudzień 2016, 12:55

Chociaż obietnice i wezwania zwrotne działają dobrze w wielu sytuacjach, uciążliwe jest wyrażenie czegoś takiego:

if (!name) {
  name = async1();
}
async2(name);

W końcu przechodziłbyś przez async1; sprawdź, czy name jest niezdefiniowane, czy nie, i odpowiednio wywołaj callback.

async1(name, callback) {
  if (name)
    callback(name)
  else {
    doSomething(callback)
  }
}

async1(name, async2)

Chociaż w małych przykładach jest to w porządku , staje się irytujące, gdy masz wiele podobnych przypadków i obsługi błędów.

Fibers pomaga w rozwiązaniu problemu.

var Fiber = require('fibers')

function async1(container) {
  var current = Fiber.current
  var result
  doSomething(function(name) {
    result = name
    fiber.run()
  })
  Fiber.yield()
  return result
}

Fiber(function() {
  var name
  if (!name) {
    name = async1()
  }
  async2(name)
  // Make any number of async calls from here
}

Możesz sprawdzić projekt Tutaj.

89
rohithpr 9 maj 2016, 13:02

ECMAScript 6 posiada „generatory”, które umożliwiają łatwe programowanie w stylu asynchronicznym.

function* myGenerator() {
    const callback = yield;
    let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback});
    console.log("response is:", response);

    // examples of other things you can do
    yield setTimeout(callback, 1000);
    console.log("it delayed for 1000ms");
    while (response.statusText === "error") {
        [response] = yield* anotherGenerator();
    }
}

Aby uruchomić powyższy kod, wykonaj następujące czynności:

const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function

Jeśli chcesz wybrać przeglądarki, które nie obsługują ES6, możesz uruchomić kod przez Babel lub kompilator zamknięcia, aby wygenerować ECMAScript 5.

Wywołania zwrotne ...args są opakowywane w tablicę i niszczone, gdy je czytasz, dzięki czemu wzorzec może poradzić sobie z wywołaniami zwrotnymi, które mają wiele argumentów. Na przykład z node fs:

const [err, data] = yield fs.readFile(filePath, "utf-8", callback);
42
James 31 lipiec 2018, 10:35

Użyj funkcji callback() wewnątrz sukcesu foo(). Spróbuj w ten sposób. Jest to proste i łatwe do zrozumienia.

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();
37
Alex Weitz 17 listopad 2017, 09:15

Oczywiście istnieje wiele podejść, takich jak synchroniczne żądanie, obietnica, ale z mojego doświadczenia wynika, że należy użyć metody wywołania zwrotnego. Asynchroniczne zachowanie JavaScript jest naturalne. Tak więc fragment kodu można przepisać nieco inaczej:

function foo() {
    var result;

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

    return result;
}

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