0
function getPrice(n){
    function onAjaxSuccess(data)
    {
        return data;
    }
    $.get(
        "prices/functions.php",
        {
            n: n
        },
        onAjaxSuccess
    );
}

Подскажите, как передать data в самой getPrice и вернуть его через return?

Kromster
  • 13,809
  • 3
    Никак. У яваскрипта нет функционала await, как у шарпа, например. Можно делать синхронный запрос, но лучше не стоит. Цепочки вызовов лучше оформлять как отдельные функции и потом запускать через .done() (документация). – etki Apr 23 '15 at 08:51
  • 1
    Как вариант: в getPrice можете передать callback, а когда ответ придет, то вызывать его. Соответственно, в callback надо будет засунуть логику, которая должна была вызываться на getPrice – BOPOH Apr 23 '15 at 09:02
  • @ВОРОН, тут и так callback передается – hardsky Apr 23 '15 at 09:03
  • @hardsky, покажите слепому - где? getPrice(n) - где здесь callback? – BOPOH Apr 23 '15 at 09:09
  • @ВОРОН, onAjaxSuccess – hardsky Apr 23 '15 at 09:26
  • Вы не внимательно читали мой комментарий: в getPrice можете передать callback. Т.е. callback должен быть не внутри ф-ии, а снаружи. Сравните: console.log(getPrice(10)) (чего хочет автор) и getPrice(10, function(price) { console.log(price); }) - мы выполняем действие не когда вызвали getPrice, а когда он готов будет выполнить наш код. Callback, конечно, надо писать отдельно, я в параметре указал для примера. – BOPOH Apr 23 '15 at 09:32
  • @ВОРОН, это попытка квадратное запихнуть в круглое, вопрос поэтому и возник, что человек зациклился на этой идее. – hardsky Apr 23 '15 at 09:39

2 Answers2

3

Если подходить к вопросу строго: jQuery поддерживает синхронные вызовы, т.е. такие, при которых выполнение скрипта прекращается, пока не получен ответ:

 var data; // в данный момент undefined
 $.ajax({
     async: false,
     url: '/',
     success: function(_data) {
         data = _data; // data указывает на переменную из внешней области видимости
     }
 });
 // так как на время выполнения $.ajax код прекратил выполнение, data уже заполнена

Однако так делать не стоит. Строго говоря, это должно заблокировать браузер до конца запроса (не знаю, как будет в реальности, и наверняка поведение различается от браузера к браузера), да и вообще парадигма яваскрипта такие штуки не предусматривает. Вместо этого в яваскрипте все делается на коллбэках (о чем вы наверняка знаете, но на всякий):

$.ajax({
    url: '/',
    success: function (data) {
        // функция, которая будет выполнена по завершению запроса
    }
})

Конечно, это не очень удобно, и становится еще менее удобным, когда в одном месте нужно сделать несколько последовательных запросов. Эта проблема решается с помощью т.н. promise - конструкции, которая выполняет тот или иной коллбек в случае удачного или неудачного завершения. В этом случае метод может вернуть этот самый promise вместо реальных данных, и клиентский код будет видеть только один объект, куда нужно подключить коллбек. Таким образом можно обернуть сразу несколько методов (attention: я в этом пока не мастер, наверняка более маститые пользователя приведут пример лучше / отредактируют этот ответ):

var api = {
    registerCustomer = function () {
        return $.ajax({ ... });
    }
    activateCustomer = function () {
        return $.ajax({ ... }));
    }
    sendGrettingLetter = function () {
        return $.ajax({ ... });
    }
};

$('register-form').on('submit', function () {
    api.registerCustomer()              // сначала выполнится этот метод
        .done(api.activateCustomer)     // после завершения - этот
        .done(api.sendGreetingLetter);  // и, наконец, финальный
});

Как в этом случае передавать вовращаемые данные - я, честно говоря, не знаю, но этот точно есть в документации, и, скорее всего, такая штука сработает:

function getCartProducts() {
    return $.ajax({ url: '/api/v1/cart' })
        .done(function (data) { return data.products; });
}
function iterateProducts(products) {
    for (var key in products) {
        // что-нибудь
    }
}

getCartProducts.done(iterateProducts);

Постараюсь до завтрашнего вечера поковырять поподробнее.

etki
  • 36,151
  • done(function (data) { return data.products; } не сработает, т.к. done просто вызывает ту функцию что вы передали, после успешного завершения ajax-а – hardsky Apr 23 '15 at 09:54
0

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

У вас скорей всего выполнение идет как-то так

function init(obj){
  obj.price = getPrice();
  obj.quantity = getQuantity();
  ...
}

можно

function init(obj){
  setPrice(obj, 100);
  setQuantity(obj, 200);
}

function setPrice(obj, n){
    function onAjaxSuccess(data)
    {
        obj.price = data;
    };

    $.get("prices/functions.php",
        {
            n: n
        },
        onAjaxSuccess
    );
}

Update:

Можно и с передачей функции, как ВОРОН предлагает

function init(){

  onSetPrice(100, funtion(){
  ...
  });
  onSetQuantity(200, function(){
  ...
  });
}

function onSetPrice(n, fn){
    $.get("prices/functions.php",{
            n: n
        },
        fn
    );
}
hardsky
  • 2,117
  • А потом, при небольшом усложнении логики (не просто obj.price = ..., а что-то более объемное), такой подход уже будет вызывать кучу проблем. Например, при получении цены надо отображать ее в карточке товара. У каждого товара своя карточка, поэтому вам придется существенно усложнять логику onAjaxSuccess. Хотя можно было бы просто передать нужную функцию, которая сама бы все делала. – BOPOH Apr 23 '15 at 10:00
  • Я бы взял backbonejs, создал там объект, указал бы ему набор событий, и onAjaxSuccess тригерил бы соответствующее событие – hardsky Apr 23 '15 at 10:10
  • @BOPOH, можно и callback-и передавать, при усложнении логики, но с событиями мне больше нравится – hardsky Apr 23 '15 at 10:36