jQuery: возвращать данные после успешного вызова ajax

У меня есть что-то вроде этого, где это простой вызов скрипта, который возвращает мне значение, строку..

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

но если я позвоню что-то вроде этого

var output = testAjax(svar);  // output will be undefined...

так как я могу вернуть значение? приведенный ниже код тоже не работает...

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

      }
   });
   return data; 
}

5 ответов

Решение

Единственный способ вернуть данные из функции - сделать синхронный вызов вместо асинхронного, но это приведет к зависанию браузера, пока он ожидает ответа.

Вы можете передать функцию обратного вызова, которая обрабатывает результат:

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

Назовите это так:

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.

Примечание. Этот ответ был написан в феврале 2010 года.
Смотрите обновления с 2015, 2016 и 2017 года внизу.

Вы не можете ничего вернуть из функции, которая является асинхронной. То, что вы можете вернуть, - это обещание. Я объяснил, как работают обещания в jQuery, в моих ответах на эти вопросы:

Если бы вы могли объяснить, почему вы хотите вернуть данные, и что вы хотите сделать с ними позже, то я мог бы дать вам более конкретный ответ, как это сделать.

Как правило, вместо:

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

Вы можете написать свою функцию testAjax следующим образом:

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

Тогда вы можете получить свое обещание так:

var promise = testAjax();

Вы можете сохранить свое обещание, вы можете передать его, вы можете использовать его в качестве аргумента в вызовах функций и вернуть его из функций, но когда вы, наконец, захотите использовать свои данные, возвращаемые вызовом AJAX, вы должны сделай это так:

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

(См. Обновления ниже для упрощенного синтаксиса.)

Если ваши данные доступны на данный момент, то эта функция будет вызвана немедленно. Если это не так, он будет вызван, как только будут доступны данные.

Весь смысл всего этого в том, что ваши данные не доступны сразу после вызова $.ajax, потому что они асинхронные. Обещания - это хорошая абстракция для функций: "Я не могу вернуть вам данные, потому что у меня их еще нет, и я не хочу блокировать и заставлять вас ждать, так что вместо этого вот обещание, и вы сможете используйте это позже, или просто дайте это кому-то еще и покончите с этим.

Смотрите это ДЕМО.

ОБНОВЛЕНИЕ (2015)

В настоящее время (по состоянию на март 2015 года) обещания jQuery не совместимы со спецификацией Promises/A+, что означает, что они могут не очень хорошо взаимодействовать с другими реализациями, соответствующими Promises/A+.

Однако jQuery Promises в следующей версии 3.x будут совместимы со спецификацией Promises/A+ (спасибо Benjamin Gruenbaum за указание на это). В настоящее время (по состоянию на май 2015 года) стабильными версиями jQuery являются 1.x и 2.x.

То, что я объяснил выше (в марте 2011 года), - это способ использовать отложенные объекты jQuery для асинхронного выполнения чего-либо, что в синхронном коде будет достигнуто путем возврата значения.

Но синхронный вызов функции может сделать две вещи - он может либо вернуть значение (если он может), либо вызвать исключение (если он не может вернуть значение). Promises/A+ обращается к обоим вариантам использования таким же мощным способом, как обработка исключений в синхронном коде. Версия jQuery обрабатывает эквивалент возврата значения просто отлично, но эквивалент сложной обработки исключений несколько проблематичен.

В частности, весь смысл обработки исключений в синхронном коде заключается не только в том, чтобы отказаться от красивого сообщения, но и в попытке исправить проблему и продолжить выполнение, или, возможно, сбросить то же или другое исключение для некоторых других частей программы, чтобы справиться. В синхронном коде у вас есть стек вызовов. В асинхронном вызове вы этого не делаете, и расширенная обработка исключений внутри ваших обещаний, как того требует спецификация Promises/A+, действительно может помочь вам написать код, который будет обрабатывать ошибки и исключения значимым образом даже для сложных случаев использования.

Различия между jQuery и другими реализациями, а также о том, как преобразовать обещания jQuery в Promises/A+ -совместимые, см. В статье " Из jQuery", автор Kris Kowal et al. В библиотеке библиотеки Q вики и Promises прибывают в JavaScript от Джейка Арчибальда на HTML5 Rocks.

Как вернуть настоящее обещание

Функция из моего примера выше:

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

возвращает объект jqXHR, который является отложенным объектом jQuery.

Чтобы вернуть реальное обещание, вы можете изменить его на - используя метод из вики Q:

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

или, используя метод из статьи HTML5 Rocks:

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

это Promise.resolve($.ajax(...)) также то, что объясняется в promise документация модуля и она должна работать с ES6 Promise.resolve(),

Для использования ES6 Promises сегодня вы можете использовать модуль es6-обещания polyfill() Джейк Арчибальд.

Чтобы узнать, где можно использовать Обещания ES6 без полизаполнения, см. " Могу ли я использовать: Обещания".

Для получения дополнительной информации см.:

Будущее jQuery

Будущие версии jQuery (начиная с 3.x - текущие стабильные версии по состоянию на май 2015 года - 1.x и 2.x) будут совместимы со спецификацией Promises/A+ (спасибо Benjamin Gruenbaum за указание на это в комментариях). "Два изменения, о которых мы уже решили, - это совместимость Promise/A+ для нашей отложенной реализации [...]" ( jQuery 3.0 и будущее веб-разработки). Для получения дополнительной информации см.: jQuery 3.0: Следующие поколения от Дейва Метвина и jQuery 3.0: Больше совместимости, меньше Internet Explorer от Пола Криля.

Интересные разговоры

ОБНОВЛЕНИЕ (2016)

В ECMA-262, 6-е издание, раздел 14.2, существует новый синтаксис , называемый функциями стрелок, который можно использовать для дальнейшего упрощения приведенных выше примеров.

Использование API jQuery вместо:

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

ты можешь написать:

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

или используя Promises/A+ API:

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

Не забывайте всегда использовать обработчики отклонения либо с:

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

или с:

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

Посмотрите этот ответ, чтобы понять, почему вы всегда должны использовать обработчики отклонений с обещаниями:

Конечно, в этом примере вы можете использовать только promise.then(alert) потому что ты просто звонишь alert с теми же аргументами, что и у вашего обратного вызова, но синтаксис стрелки является более общим и позволяет писать такие вещи, как:

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

Не каждый браузер поддерживает этот синтаксис, но есть определенные случаи, когда вы уверены, в каком браузере будет работать ваш код - например, при написании расширения Chrome, дополнения Firefox или настольного приложения с использованием Electron, NW.js или AppJS (подробности см. В этом ответе).

Для поддержки функций стрелок см.:

ОБНОВЛЕНИЕ (2017)

Сейчас существует еще более новый синтаксис, называемый асинхронными функциями с новым await Ключевое слово, которое вместо этого кода:

functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

позволяет вам написать:

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

Вы можете использовать его только внутри функции, созданной с помощью async ключевое слово. Для получения дополнительной информации см.:

Для поддержки в браузерах, смотрите:

Для поддержки в узле см.:

В местах, где у вас нет собственной поддержки async а также await Вы можете использовать Babel:

или с немного другим синтаксисом подход на основе генератора, как в co или сопрограммы Bluebird:

Больше информации

Некоторые другие вопросы об обещаниях для более подробной информации:

Вы можете добавить асинхронную опцию в false и вернуться за пределы вызова ajax.

function testAjax() {
    var result="";
    $.ajax({
      url:"getvalue.php",
      async: false,  
      success:function(data) {
         result = data; 
      }
   });
   return result;
}

ИДК, если вы, ребята, решили это, но я рекомендую другой способ сделать это, и это работает:)

    ServiceUtil = ig.Class.extend({
        base_url : 'someurl',

        sendRequest: function(request)
        {
            var url = this.base_url + request;
            var requestVar = new XMLHttpRequest();
            dataGet = false;

            $.ajax({
                url: url,
                async: false,
                type: "get",
                success: function(data){
                    ServiceUtil.objDataReturned = data;
                }
            });
            return ServiceUtil.objDataReturned;                
        }
    })

Таким образом, основная идея заключается в том, что, добавив async: false, вы заставляете все ждать, пока данные не будут получены. Затем вы назначаете его статической переменной класса, и все волшебным образом работает:)

См. Пример документации jquery: http://api.jquery.com/jQuery.ajax/(около 2/3 страницы)

Возможно, вы ищете следующий код:

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

Та же страница... опустить вниз.

Другие вопросы по тегам