Ajax error undefined

I'm sure you know this problem, I'm still trying to solve it for few days. I've tried lots of stuff but no one worked: Here is the code function lobbyLeader() { $.ajax({ data: {"id": 1, "

I’m sure you know this problem, I’m still trying to solve it for few days. I’ve tried lots of stuff but no one worked:

Here is the code

function lobbyLeader() {
    $.ajax({
       data: {"id": 1, "request": "lobbyinfo", "method": "read"},
       url: 'api.php',
       dataType: 'json',
       success: function(data){
           result = data.leader;
           return result;
       }
   });
}

alert(result); will show 1 but when using in an other function it says undefined.

Alexander's user avatar

Alexander

23.3k11 gold badges61 silver badges73 bronze badges

asked Jan 2, 2011 at 20:10

Nightbox's user avatar

5

You can’t return from an asynchronous function like this, you’re returning from that success callback function, not the parent function. Instead, kick off whatever you need in the callback, like this:

function lobbyLeader() {
  $.ajax({
    data: {"id": 1, "request": "lobbyinfo", "method": "read"},
    url: 'api.php',
    dataType: 'json',
    success: function(data){
      someOtherFunc(data.leader);
   }
 });
}

answered Jan 2, 2011 at 20:15

Nick Craver's user avatar

Nick CraverNick Craver

619k136 gold badges1293 silver badges1152 bronze badges

7

Correctly stated that you can’t really return from the Success, however, if you are doing what I think you are doing, and that is to grab the data and return it and assign it to something in another area IE

var obj = lobbyLeader();

Then you can just set the function to async:false and return the obj outside of the Success after the code has finished running.
example

function lobbyLeader() {
var obj;
  $.ajax({
    async:false;
    data: {"id": 1, "request": "lobbyinfo", "method": "read"},
    url: 'api.php',
    dataType: 'json',
    success: function(data){
      obj= JSON.parse(data);
   }
 });
    return obj;
}

This way the script stops to wait for success and then sets and returns.

answered Mar 31, 2016 at 20:08

matt's user avatar

mattmatt

911 silver badge1 bronze badge

2

The problem here is that AJAX is asynchronous (it’s what the first A stands for). This means that the function returns immediately; the success handler is only called when the request is successful. This means that lobbyLeader returns immediately after you have made your request, so returns nothing.

If you have any code that needs to run after you have received the data, it must be placed in the success handler (or another AJAX event handler) or be invoked by it.

answered Jan 2, 2011 at 20:14

lonesomeday's user avatar

lonesomedaylonesomeday

230k49 gold badges313 silver badges315 bronze badges

I recommend this way.

  1. use the ajax call by the async:false.
  2. move the return statement after the ajax call.

Example :

function makeJQGridDataFromList(url)
{
    var rowData;
    var viewPage = 0;
    var viewTotal = 0;
    var viewRecords = 0;

    var resultObject;

    $.ajax({    
        type:"GET",
        url:url,    
        async: false,
        success:function(args){ 
            if(args.result==true)
            {
                try
                {
                    viewPage = args.cond.pageIndex;
                    viewTotal = args.cond.recordCountPerPage;
                    viewRecords = args.cond.totalCnt;

                    rowData = jsonMakeRowsForGrid(args.data);
                }
                catch (e)
                {
                    console.debug("Error!");
                    alert("Invalid data");
                    return;
                }
            } else
            {
                alert("API return ERROR!");
                return;
            }
        }, 
        error:function(e){
            alert("Fail AJAX communication");
            return;
        }
    });

    resultObject = {
        page : viewPage,
        total : viewTotal,
        records : viewRecords,
        rows : rowData
    };

    return(resultObject);
}

You can test the following method.

(In the other file (html or js))

var gridData = makeJQGridDataFromList(openAPIUrl);
console.debug(">> " + JSON.stringify(gridData));

You can see the gridData.

I faced same problems. :)

answered Mar 20, 2014 at 8:45

mass's user avatar

massmass

714 bronze badges

When you return values from within an anonymous function that is executed asynchronously, those values will not propogate up the scope chain, the return statement is only applied on the current function scope, not the surrounding scope, $.ajax() is asynchronous, so immediately after executing the statement, the outer function returns, so there is no return value of the outer function, that’s why you’re getting undefined.

The only way to hook into a possible return value from the callback function passed to $.ajax is to invoke another outer function, passing in the desired data.

answered Jan 2, 2011 at 20:15

Jacob Relkin's user avatar

Jacob RelkinJacob Relkin

160k33 gold badges343 silver badges318 bronze badges

Здравствуйте! Никак не могу решить проблему с ajax — постоянно возвращает «undefined». Хочу сразу отметить, что даже если пробовать вывести json через console.log — получается тоже самое.

Код:

$.ajax({
        type: 'GET',
        url: '../Data/Scripts/GetTrackInfo.php',
        async: true,
        data:'track_hash=760e07bb98d02f0887f20f7ba75e7581',
        contentType: "application/json",
        dataType: 'json',
 success: function(json) {
         var track_name = json['track_name'];
         var track_author = json['track_author'];
         $('#latest-tracks').html('<div class="list-group"><a class="list-group-item"><strong>Название:</strong>'+track_author+' - '+track_name+'</a></div>');
  },
  error: function(e) {
         console.log(e.message)
   }
})

Json на сервере формирую при помощи json_encode. Если обратиться к php скрипту напрямую, через адресную строку, json успешно выводится:

{
	"track_name": "Smoke Gang Costra Nostra [Feat El Pablo]",
	"track_hash": "760e07bb98d02f0887f20f7ba75e7581",
	"track_url": "DJ Smokey - Smoke Gang Costra Nostra [Feat El Pablo]",
	"track_bitrate": "245",
	"track_author": "DJ Smokey",
	"cover": "../Data/Covers/Template/none.jpg",
	"track_url2": "DJ+Smokey+-+Smoke+Gang+Costra+Nostra",
	"track_album": "Single",
	"album_hash": "",
	"track_downloads": "0",
	"track_playtime": "04:52",
	"track_genre": "Relax"
}

30 ответов

ответ дан David Pine 17 August 2018 в 10:05

поделиться

Мы оказываемся во вселенной, которая, по-видимому, развивается по измерению, которое мы называем «временем». Мы не понимаем, какое время, но мы разработали абстракции и словарный запас, которые позволяют рассуждать и говорить об этом: «прошлое», «настоящее», «будущее», «до», «после».

Компьютерные системы, которые мы строим — все больше и больше — имеют время как важное измерение. В будущем будут созданы определенные вещи. Тогда другие вещи должны произойти после того, как эти первые вещи в конечном итоге произойдут. Это основное понятие, называемое «асинхронность». В нашем мире с более сложной сетью наиболее распространенный случай асинхронности ожидает, что какая-то удаленная система ответит на какой-либо запрос.

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

var milk = order_milk();
put_in_coffee(milk);

Поскольку JS не знает, что ему нужно дождаться окончания order_milk, прежде чем он выполнит put_in_coffee. Другими словами, он не знает, что order_milk является асинхронным — это то, что не приведет к молоку до некоторого будущего времени. JS и другие декларативные языки, выполняйте один оператор за другим, не ожидая.

Классический подход JS к этой проблеме, используя тот факт, что JS поддерживает функции как объекты первого класса, которые могут быть переданы, заключается в передаче функции в качестве параметра для асинхронного запроса, который затем будет вызываться, когда он будет выполнять свою задачу в будущем. Это подход «обратного вызова». Это выглядит так:

order_milk(put_in_coffee);

order_milk запускает, заказывает молоко, тогда, когда и только когда он прибывает, он вызывает put_in_coffee.

Проблема с этот подход обратного вызова состоит в том, что он загрязняет нормальную семантику функции, сообщающей свой результат с помощью return; вместо этого функции должны сообщать свои результаты, вызывая обратный вызов, заданный как параметр. Кроме того, этот подход может быстро стать громоздким при работе с более длинными последовательностями событий. Например, предположим, что я хочу дождаться, когда молоко будет помещено в кофе, а затем и только затем выполните третий шаг, а именно — выпить кофе. В конце концов мне нужно написать что-то вроде этого:

order_milk(function(milk) { put_in_coffee(milk, drink_coffee); }

, где я перехожу к put_in_coffee как к молоку, чтобы положить в него, так и к действию (drink_coffee), чтобы выполнить как только молоко был введен. Такой код становится трудно писать, читать и отлаживать.

В этом случае мы могли бы переписать код в вопросе как:

var answer;
$.ajax('/foo.json') . done(function(response) {
  callback(response.data);
});

function callback(data) {
  console.log(data);
}

Enter обещает

. Это была мотивация для понятия «обещание», которое является особым типом ценности, представляющим собой будущий или асинхронный результат какого-то рода. Он может представлять что-то, что уже произошло, или это произойдет в будущем, или, возможно, никогда не произойдет вообще. Обещания имеют один метод, названный then, которому вы передаете действие, которое должно быть выполнено, когда был достигнут результат, представленный обещанием.

В случае нашего молока и кофе мы создаем order_milk, чтобы вернуть обещание о прибытии молока, затем укажите put_in_coffee как действие then следующим образом:

order_milk() . then(put_in_coffee)

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

order_milk() . then(put_in_coffee) . then(drink_coffee)

Давайте применим обещания к вашей конкретной проблеме. Мы завершим нашу логику запроса внутри функции, которая возвращает обещание:

function get_data() {
  return $.ajax('/foo.json');
}

На самом деле, все, что мы сделали, добавлено к return к вызову $.ajax. Это работает, потому что jQuery $.ajax уже возвращает вид обетоподобной вещи. (На практике, не вдаваясь в подробности, мы предпочли бы обернуть этот вызов, чтобы вернуть реальное обещание, или использовать некоторую альтернативу $.ajax, которая делает это.) Теперь, если мы хотим загрузить файл и дождаться его завершите, а затем сделайте что-нибудь, мы можем просто сказать

get_data() . then(do_something)

, например,

get_data() . 
  then(function(data) { console.log(data); });

. При использовании обещаний мы заканчиваем передачу множества функций в then, поэтому часто полезно использовать более компактные функции стрелок в стиле ES6:

get_data() . 
  then(data => console.log(data));

Ключевое слово async

Но все еще есть что-то неопределенное в том, что нужно писать код одним способом, если синхронно и совершенно по-другому, если асинхронно. Для синхронного мы пишем

a();
b();

, но если a является асинхронным, с обещаниями мы должны написать

a() . then(b);

Выше, мы сказали: «JS не имеет никакого способа узнать что ему нужно дождаться завершения первого вызова, прежде чем он выполнит второй ». Было бы неплохо, если бы можно было сказать JS? Оказывается, существует ключевое слово await, используемое внутри специального типа функции, называемого функцией «async». Эта функция является частью предстоящей версии ES, но уже доступна в транспилерах, таких как Babel, с учетом правильных настроек. Это позволяет нам просто написать

async function morning_routine() {
  var milk   = await order_milk();
  var coffee = await put_in_coffee(milk);
  await drink(coffee);
}

. В вашем случае вы могли бы написать что-то вроде

async function foo() {
  data = await get_data();
  console.log(data);
}

ответ дан 3 revs, 2 users 95%user663031 17 August 2018 в 10:05

поделиться

Используйте функцию callback() внутри успеха foo(). Попробуйте таким образом. Это просто и легко понять. & nbsp;

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

ответ дан Alex Weitz 17 August 2018 в 10:05

поделиться

Это одно из мест, с помощью которого привязка данных, используемая во многих новых фреймворках JavaScript, будет очень полезна для вас …

Итак, если вы используете Angular, React или любые другие фреймворки, которые делают два способа связывания данных, эта проблема просто исправлена ​​для вас, поэтому простым языком ваш результат undefined на первом этапе, поэтому вы получили result = undefined до получения данных, а затем, как только вы получите результат , он будет обновляться и присваиваться новому значению, которое отвечает на ваш вызов Ajax …

Но как вы можете сделать это в чистом javascript или jQuery, например, как вы задали этот вопрос?

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

Например, в вашем случае, в котором вы используете jQuery, вы можете сделать что-то вроде этого:

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

Для получения дополнительной информации n изучение обещаний и наблюдаемых, которые являются новыми способами для создания асинхронных материалов.

ответ дан Alireza 17 August 2018 в 10:05

поделиться

Другое решение состоит в том, чтобы выполнить код через последовательный исполнитель nsynjs .

Если базовая функция многозначна

nsynjs будет последовательно оценивать все обещания и ставить обещания результат в свойство data:

function synchronousCode() {

    var getURL = function(url) {
        return window.fetch(url).data.text().data;
    };
    
    var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
    console.log('received bytes:',getURL(url).length);
    
};

nsynjs.run(synchronousCode,{},function(){
    console.log('synchronousCode done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

Если базовая функция не обещает

Шаг 1. Wrap с обратным вызовом в оболочку, совместимую с nsynjs (если у нее есть обещанная версия, вы можете пропустить этот тест):

var ajaxGet = function (ctx,url) {
    var res = {};
    var ex;
    $.ajax(url)
    .done(function (data) {
        res.data = data;
    })
    .fail(function(e) {
        ex = e;
    })
    .always(function() {
        ctx.resume(ex);
    });
    return res;
};
ajaxGet.nsynjsHasCallback = true;

Шаг 2. Вставить синхронную логику в функцию:

function process() {
    console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}

Шаг 3. Выполнить функцию синхронно через nnsynjs:

nsynjs.run(process,this,function () {
    console.log("synchronous function finished");
});

Nsynjs будет оценивать все операторы и выражения шаг за шагом, приостанавливая выполнение в случае, если результат некоторой медленной функции не готов.

Дополнительные примеры здесь: https://github.com/amaksr/nsynjs/tree/master/examples

ответ дан amaksr 17 August 2018 в 10:05

поделиться

Js — однопоточная.

Браузер можно разделить на три части:

1) Event Loop

2 ) Web API

3) Очередь событий

Событие Loop запускается вечно, т. Е. Тип бесконечного цикла. Очередь ожидания — это то, где вся ваша функция нажимается на какое-либо событие (пример: нажмите) this один за другим выполняется в очереди и помещается в цикл «Событие», который выполняет эту функцию и подготавливает ее для следующего после первого запуска. Это означает, что выполнение одной функции не начинается до тех пор, пока функция, перед которой она в очереди не будет выполнена цикл событий.

Теперь давайте подумаем, что мы поставили две функции в очереди, чтобы получить данные с сервера, а другой использует эти данные. Мы сначала нажали функцию serverRequest () в очереди, а затем применили функцию Data () , Функция serverRequest переходит в цикл событий и делает вызов на сервер, так как мы никогда не знаем, сколько времени потребуется для получения данных с сервера, поэтому ожидается, что этот процесс займет много времени, и поэтому мы заняли наш цикл событий, тем самым повесив нашу страницу, вот где Web API входит в эту роль, он принимает эту функцию из цикла событий и обращается к серверу, создающему цикл событий, так что мы можем выполнить следующую функцию из очереди. Следующая функция в очереди — useData (), которая идет в цикле, но из-за отсутствия данных отходы и выполнение следующей функции продолжаются до конца очереди (это называется Async-вызовом, то есть мы можем сделать что-то еще, пока не получим данные)

Предположим, что наша функция serverRequest () имела оператор возврата в код, когда мы возвращаем данные с сервера Web API, будет выталкивать его в очередь в конце очереди. По мере того, как он заканчивается в очереди, мы не можем использовать его данные, поскольку в нашей очереди нет функции, чтобы использовать эти данные. Таким образом, невозможно вернуть что-то из Async Call.

Таким образом, решение этой проблемы callback или обещают .

A Изображение из одного из ответов здесь, правильно объясняет использование обратного вызова … Мы (функция, использующая данные, возвращаемые с сервера), чтобы вызвать вызывающий сервер.

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}

В моем коде он называется

function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}

Прочитайте здесь новые методы в ECMA (2016/17) для создания асинхронного вызова (@Felix Kling Answer сверху) https://stackoverflow.com/a/14220323/7579856

ответ дан Aniket Jha 17 August 2018 в 10:05

поделиться

Это очень распространенная проблема, с которой мы сталкиваемся, борясь с «таинствами» JavaScript.

Давайте начнем с простой функции JavaScript:

function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here

Это простой синхронный вызов функции (где каждая строка кода выполняется одна за другой в последовательность), и результат будет таким же, как ожидалось.

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

function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

Итак, вы идете, эта задержка просто сломала функциональность, которую мы ожидали! Но что именно произошло? Ну, на самом деле это довольно логично, если вы посмотрите на код. функция foo() после выполнения ничего не возвращает (таким образом, возвращаемое значение равно undefined), но оно запускает таймер, который выполняет функцию после 1s, чтобы вернуть «wohoo». Но, как вы можете видеть, значение, присвоенное бару, является немедленно возвращенным материалом из foo (), а не что-либо еще, что приходит позже.

Итак, как мы решаем эту проблему?

Давайте попросим нашу функцию для ОБЕЩАНИЯ. Обещание действительно о том, что это означает: это означает, что функция гарантирует, что вы предоставите любой результат, который он получит в будущем. поэтому давайте посмотрим на это в нашей маленькой проблеме выше:

function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when exececution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});

Таким образом, резюме — для решения асинхронных функций, таких как вызовы на основе ajax и т. д., вы можете использовать обещание resolve значение (которое вы намерены вернуть). Таким образом, короче говоря, вы разрешаете значение вместо возврата в асинхронных функциях.

ответ дан Anish K. 17 August 2018 в 10:05

поделиться

Самое простое решение — создать функцию JavaScript и вызвать его для обратного вызова 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);    
}); 

ответ дан clearlight 17 August 2018 в 10:05

поделиться

ответ дан Community 17 August 2018 в 10:05

поделиться

Краткий ответ: ваш метод foo() возвращается немедленно, а вызов $ajax() выполняется асинхронно после возврата функции . Проблема заключается в том, как и где сохранить результаты, полученные при вызове async, после его возврата.

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

function foo(result) {
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;   // Store the async result
        }
    });
}

var result = { response: null };   // Object to hold the async result
foo(result);                       // Returns before the async completes

Обратите внимание, что вызов foo() ] все равно не вернут ничего полезного. Однако результат асинхронного вызова теперь будет сохранен в result.response.

ответ дан David R Tribble 17 August 2018 в 10:05

поделиться

Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.

Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.

  1. Ваша точка входа (ов) выполняется в результате события. Например, в браузер загружается тег сценария с кодом. (Соответственно, поэтому вам, возможно, придется заботиться о готовности страницы запускать ваш код, если он требует, чтобы элементы dom были сконструированы первыми и т. Д.)
  2. Ваш код выполняется до завершения, однако многие асинхронные вызовы, которые он делает, без выполнения каких-либо ваших обратных вызовов, включая запросы XHR, установку тайм-аутов, обработчиков событий dom и т. д. Каждый из этих обратных вызовов, ожидающих выполнения, будет находиться в очереди, ожидая, что их очередь будет запущена после других событий
  3. Каждый отдельный обратный вызов XHR-запроса, установленного таймаута или dom события после вызова будет завершен.

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

Но вы не должны использовать какие-либо тактические инструменты для решения проблемы, пока вам не понравится актуальная проблемная область. Нарисуйте карту этих зависимостей, чтобы знать, что нужно запускать, когда. Попытка ad-hoc подхода ко всем этим обратным вызовам просто не поможет вам.

ответ дан eFarzad 17 August 2018 в 10:05

поделиться

Используя ES2017, вы должны иметь это как объявление функции

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

и выполнить его следующим образом.

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

Или синтаксис Promise

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

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

})

ответ дан Fernando Carvajal 17 August 2018 в 10:05

поделиться

ECMAScript 6 имеет «генераторы», которые позволяют вам легко программировать в асинхронном стиле.

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

Для запуска вышеуказанного кода вы делаете это:

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

Если вам нужно настроить таргетинг на браузеры, которые не поддерживают ES6, вы можете запустить код через Babel или short-compiler для генерации ECMAScript 5.

Обратный вызов ...args завернут в массив и разрушен, когда вы их читаете так что шаблон может справиться с обратными вызовами, которые имеют несколько аргументов. Например, с узлом fs :

const [err, data] = yield fs.readFile(filePath, "utf-8", callback);

ответ дан James 17 August 2018 в 10:05

поделиться

Большинство ответов здесь дают полезные советы, когда у вас есть одна операция async, но иногда это возникает, когда вам нужно выполнить асинхронную операцию для каждой записи в массиве или другом списке подобная структура. Искушение состоит в том, чтобы сделать это:

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

Пример:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Причина, ‘t работа заключается в том, что обратные вызовы из doSomethingAsync еще не запущены к тому моменту, когда вы пытаетесь использовать результаты.

Итак, если у вас есть массив (или список какого-то типа) и хотите выполнять асинхронные операции для каждой записи, у вас есть два варианта: выполнять операции параллельно (перекрывающиеся) или последовательно (последовательно последовательно).

Параллельный

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

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

Пример:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Мы могли бы покончить с expecting и просто использовать results.length === theArray.length, но это оставляет нам открытым возможность того, что theArray изменяется, пока вызовы выдающиеся …)

Обратите внимание, как мы используем index из forEach, чтобы сохранить результат в results в том же положении, что и запись это относится, даже если результаты a (поскольку асинхронные вызовы не обязательно завершаются в том порядке, в котором они были запущены).

Но что, если вам нужно вернуть те результаты от функции? Как указывали другие ответы, вы не можете; вы должны принять вашу функцию и вызвать обратный вызов (или вернуть Promise ). Вот вариант обратного вызова:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Или вот версия, возвращающая Promise вместо:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Конечно, если doSomethingAsync передал нам ошибки, мы использовали бы reject, чтобы отклонить обещание, когда мы получили сообщение об ошибке.)

Пример:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Или, альтернативно, вы можете сделать обертку для doSomethingAsync, который возвращает обещание, а затем сделайте следующее …)

Если doSomethingAsync дает вам Promise , вы можете использовать Promise.all :

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Обратите внимание, что Promise.all решает свое обещание с помощью массива результатов всех обещаний, которые вы даете ему, когда все они разрешены, или отвергает его обещание, когда первый обещаний, которые вы ему даете, отклоняет.

Серия

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

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(Поскольку мы выполняем работу последовательно, мы можем просто использовать results.push(result), так как мы знаю, что мы не получим результаты не в порядке. В приведенном выше примере мы могли бы использовать results[index] = result;, но в некоторых из следующих примеров у нас нет индекса для использования.)

Пример:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Или снова создайте обертку для doSomethingAsync, которая дает вам обещание и выполните ниже …)

Если doSomethingAsync дает вам обещание, если вы можете использовать синтаксис ES2017 + (возможно, с транспилером, например Babel ), вы можете использовать функцию async с помощью for-of и await :

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Пример:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Если вы не можете использовать синтаксис ES2017 + (пока), вы можете использовать вариацию на Обещают уменьшить шаблон (это сложнее, чем обычное сокращение Promise, потому что мы не передаем результат от одного к другому, а вместо gat

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

.. , который менее громоздк с функциями стрелок ES2015 + :

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Пример:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

ответ дан Joel Gritter 17 August 2018 в 10:05

поделиться

Я отвечу ужасным, нарисованным рукой комиком. Второе изображение является причиной того, что result является undefined в вашем примере кода.

ответ дан Johannes Fahrenkrug 17 August 2018 в 10:05

поделиться

В следующем примере, который я написал, показано, как

  • обрабатывать асинхронные HTTP-вызовы;
  • Подождать ответа от каждого вызова API;
  • Использовать шаблон promise ;
  • Используйте шаблон Promise.All для объединения нескольких HTTP-вызовов;

Этот рабочий пример является автономным. Он будет определять простой объект запроса, который использует объект window XMLHttpRequest для совершения вызовов. Он будет определять простую функцию, чтобы дождаться завершения кучи обещаний.

Контекст. В этом примере запрашивается конечная точка Spotify Web API для поиска объектов playlist для заданного набора строк запроса:

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

Для каждого элемента новый Promise запустит блок — ExecutionBlock, проанализирует результат, заплатит новый набор обещаний на основе массива результатов, который представляет собой список объектов Spotify user и выполняет новый HTTP-вызов в ExecutionProfileBlock асинхронно.

Затем вы можете увидеть вложенную структуру Promise, которая позволяет вам генерировать множественные и полностью асинхронные вложенные HTTP-вызовы и присоединять результаты к каждому подмножеству вызовов через Promise.all.

NOTE Recent Spotify search API-интерфейсам потребуется указать токен доступа в заголовках запроса:

-H "Authorization: Bearer {your access token}" 

Итак, вы должны запустить следующий пример, вам нужно поместить маркер доступа в заголовки запроса:

var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "<br/>"
    }
}

// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
    call: function(what, response) {
        var request;
        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // Internet Explorer
            try {
                request = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
                try {
                  request = new ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {}
            }
        }

        // State changes
        request.onreadystatechange = function() {
            if (request.readyState === 4) { // Done
                if (request.status === 200) { // Complete
                    response(request.responseText)
                }
                else
                    response();
            }
        }
        request.open('GET', what, true);
        request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
        request.send(null);
    }
}

//PromiseAll
var promiseAll = function(items, block, done, fail) {
    var self = this;
    var promises = [],
                   index = 0;
    items.forEach(function(item) {
        promises.push(function(item, i) {
            return new Promise(function(resolve, reject) {
                if (block) {
                    block.apply(this, [item, index, resolve, reject]);
                }
            });
        }(item, ++index))
    });
    Promise.all(promises).then(function AcceptHandler(results) {
        if (done) done(results);
    }, function ErrorHandler(error) {
        if (fail) fail(error);
    });
}; //promiseAll

// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
    var url = "https://api.spotify.com/v1/"
    url += item;
    console.log( url )
    SimpleRequest.call(url, function(result) {
        if (result) {

            var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
                return item.owner.href;
            })
            resolve(profileUrls);
        }
        else {
            reject(new Error("call error"));
        }
    })
}

arr = [
    "search?type=playlist&q=%22doom%20metal%22",
    "search?type=playlist&q=Adele"
]

promiseAll(arr, function(item, index, resolve, reject) {
    console.log("Making request [" + index + "]")
    ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results

    console.log("All profiles received " + results.length);
    //console.log(JSON.stringify(results[0], null, 2));

    ///// promiseall again

    var ExecutionProfileBlock = function(item, index, resolve, reject) {
        SimpleRequest.call(item, function(result) {
            if (result) {
                var obj = JSON.parse(result);
                resolve({
                    name: obj.display_name,
                    followers: obj.followers.total,
                    url: obj.href
                });
            } //result
        })
    } //ExecutionProfileBlock

    promiseAll(results[0], function(item, index, resolve, reject) {
        //console.log("Making request [" + index + "] " + item)
        ExecutionProfileBlock(item, index, resolve, reject);
    }, function(results) { // aggregated results
        console.log("All response received " + results.length);
        console.log(JSON.stringify(results, null, 2));
    }

    , function(error) { // Error
        console.log(error);
    })

    /////

  },
  function(error) { // Error
      console.log(error);
  });
<div id="console" />

Я подробно рассмотрел это решение здесь .

ответ дан loretoparisi 17 August 2018 в 10:05

поделиться

Angular1

Для людей, которые используют AngularJS , может справиться с этой ситуацией, используя Promises.

Здесь it говорит,

Обещания могут использоваться для отключения асинхронных функций и позволяют объединять несколько функций вместе.

Вы можете найти приятное объяснение здесь .

Пример, найденный в docs , упомянутом ниже.

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

Angular2 and Later

In Angular2, посмотрите на следующий пример, но его рекомендовал использовать Observables с Angular2.

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

Вы можете использовать это таким образом,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

См. здесь оригинал . Но TypScript не поддерживает native es6 Promises , если вы хотите его использовать, для этого вам может понадобиться плагин.

Кроме того, здесь представлены обещания spec определите здесь.

ответ дан Maleen Abewardana 17 August 2018 в 10:05

поделиться

Вместо того, чтобы бросать код на вас, есть два понятия, которые являются ключом к пониманию того, как JS обрабатывает обратные вызовы и асинхронность. (это даже слово?)

Модель цикла события и параллелизма

Есть три вещи, о которых вам нужно знать; Очередь; цикл события и стек

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

while (queue.waitForMessage()) {
   queue.processNextMessage();
}

Как только он получает сообщение для запуска чего-то, он добавляет его в очередь. Очередь — это список вещей, которые ждут выполнения (например, ваш запрос AJAX). Представьте себе это так:

 1. call foo.com/api/bar using foobarFunc
 2. Go perform an infinite loop
 ... and so on

Когда одно из этих сообщений будет исполнено, оно выталкивает сообщение из очереди и создает стек, стек — это все, что нужно выполнить JS для выполнения инструкции в сообщение. Таким образом, в нашем примере ему говорят позвонить foobarFunc

function foobarFunc (var) {
  console.log(anotherFunction(var));
}

. Так что все, что foobarFunc должно выполнить (в нашем случае anotherFunction), будет вставлено в стек. исполняемый, а затем забытый — цикл события затем переместится на следующую вещь в очереди (или прослушивает сообщения)

. Главное здесь — порядок выполнения. Это

КОГДА что-то будет запущено

Когда вы совершаете вызов с использованием AJAX для внешней стороны или выполняете любой асинхронный код (например, setTimeout), Javascript зависит от ответ, прежде чем он сможет продолжить.

Большой вопрос, когда он получит ответ? Ответ в том, что мы не знаем, поэтому цикл событий ждет, когда это сообщение скажет: «Эй, забери меня». Если JS просто ждал этого сообщения синхронно, ваше приложение замерзнет, ​​и оно сосать. Таким образом, JS продолжает выполнение следующего элемента в очереди, ожидая, пока сообщение не будет добавлено обратно в очередь.

Вот почему с асинхронной функциональностью мы используем вещи, называемые обратными вызовами. Это похоже на обещание буквально. Как и в I , обещание что-то вернуть в какой-то момент jQuery использует специальные обратные вызовы, называемые deffered.done deffered.fail и deffered.always (среди других). Вы можете увидеть их все здесь

Итак, вам нужно передать функцию, которая в какой-то момент будет выполнена с переданными ей данными.

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

function foo(bla) {
  console.log(bla)
}

, поэтому большую часть времени (но не всегда) вы пройдете foo не foo()

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

ответ дан Matthew Brent 17 August 2018 в 10:05

поделиться

Конечно, есть много таких подходов, как синхронный запрос, обещание, но из моего опыта я думаю, что вы должны использовать подход обратного вызова. Естественно, что асинхронное поведение Javascript. Итак, ваш фрагмент кода можно переписать немного иначе:

function foo() {
    var result;

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

    return result;
}

function myCallback(response) {
    // Does something.
}

ответ дан Michał Perłakowski 17 August 2018 в 10:05

поделиться

2017 ответ: теперь вы можете делать то, что хотите, в каждом текущем браузере и узле

. Это довольно просто:

  • Вернуть обещание
  • Используйте ‘await’ , в котором JavaScript ожидает, что обещание будет разрешено в vlue (например, hTTP-ответ)
  • Добавьте ‘async’ для родительской функции

Вот рабочая версия вашего кода:

(async function(){

var response = await superagent.get('...')
console.log(response)

})()

ожидание поддерживается во всех текущих браузерах и узлах 8 [/ д2]

ответ дан mikemaccana 17 August 2018 в 10:05

поделиться

Вот некоторые подходы к работе с асинхронными запросами:

  1. Объект обезьяны браузера
  2. Q — A
  3. A + Promises.js
  4. jQuery отложен
  5. API XMLHttpRequest
  6. Использование концепции обратного вызова — как реализация в первом ответе

Пример: jQuery отложенная реализация для работы с несколькими запросами

var App = App || {};

App = {
    getDataFromServer: function(){

      var self = this,
                 deferred = $.Deferred(),
                 requests = [];

      requests.push($.getJSON('request/ajax/url/1'));
      requests.push($.getJSON('request/ajax/url/2'));

      $.when.apply(jQuery, requests).done(function(xhrResponse) {
        return deferred.resolve(xhrResponse.result);
      });
      return deferred;
    },

    init: function(){

        this.getDataFromServer().done(_.bind(function(resp1, resp2) {

           // Do the operations which you wanted to do when you
           // get a response from Ajax, for example, log response.
        }, this));
    }
};
App.init();

ответ дан Mohan Dere 17 August 2018 в 10:05

поделиться

Короткий ответ: вам нужно выполнить обратный вызов следующим образом:

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

$.ajax({
    url: "...",
    success: callback
});

ответ дан Pablo Matias Gomez 17 August 2018 в 10:05

поделиться

Вы можете использовать эту пользовательскую библиотеку (написанную с помощью Promise) для выполнения удаленного вызова.

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

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

$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});

ответ дан Peter Mortensen 17 August 2018 в 10:05

поделиться

Вопрос был:

Как вернуть ответ от асинхронного вызова?

, который может быть интерпретирован как:

< blockquote>

Как сделать синхронный асинхронный код синхронным?

Решение будет состоять в том, чтобы избежать обратных вызовов и использовать комбинацию Promises и async / await.

Я хотел бы привести пример для запроса Ajax.

(Хотя он может быть записан в Javascript, я предпочитаю писать его на Python и компилировать его в Javascript, используя Transcrypt . Это будет достаточно ясно.)

Позволяет сначала включить использование JQuery, чтобы $ был доступен как S:

__pragma__ ('alias', 'S', '$')

Определить функцию, которая возвращает Promise, в этом случае вызов Ajax:

def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()

Использовать асинхронный код, как если бы он был синхронным:

async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")

ответ дан Pieter Jan Bonestroo 17 August 2018 в 10:05

поделиться

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

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

. В итоге вы пройдете через async1; проверьте, не определено ли name или нет, и соответственно вызовите обратный вызов.

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

async1(name, async2)

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

Fibers помогает в решении проблемы.

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
}

Вы можете проверить проект здесь .

ответ дан rohithpr 17 August 2018 в 10:05

поделиться

Посмотрите на этот пример:

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

Как вы можете видеть, getJoke возвращает разрешенное обещание (оно разрешено при возврате res.data.value). Таким образом, вы ждете, пока запрос $ http.get не будет завершен, а затем выполнится console.log (res.joke) (как обычный асинхронный поток).

Это plnkr:

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

ответ дан Super User 17 August 2018 в 10:05

поделиться

Если вы не используете jQuery в своем коде, этот ответ для вас

Ваш код должен быть чем-то вроде этого:

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

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

Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery для AJAX, я решил предоставить альтернативу для людей, которые этого не делают.

( Примечание. используя новый API fetch, угловые или обещания, я добавил еще один ответ ниже )


То, с чем вы столкнулись

Это краткое резюме «Объяснение проблемы» из другого ответа, если вы не уверены, прочитав это, прочитайте это.

A в AJAX означает асинхронность. Это означает, что отправка запроса (или, скорее, получение ответа) вынимается из обычного потока выполнения. В вашем примере .send немедленно возвращается, а следующий оператор return result; выполняется до того, как функция, которую вы передали, когда был вызван обратный вызов success.

Это означает когда вы возвращаетесь, слушатель, который вы определили, еще не выполнил, что означает, что возвращаемое вами значение не было определено.

Вот простая аналогия

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

(Fiddle)

Возвращаемое значение aundefined так как часть a=5 еще не выполнена. AJAX действует так, вы возвращаете значение до того, как сервер получил возможность сообщить вашему браузеру, что это за значение.

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

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

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

Это называется CPS . В основном, мы передаем getFive действие, которое необходимо выполнить, когда оно завершается, мы сообщаем нашему кодексу, как реагировать, когда событие завершается (например, наш вызов AJAX или в этом случае время ожидания).

Использование будет:

getFive(onComplete);

Который должен предупредить «5» на экране. (Fiddle) .

Возможные решения

Существуют два способа решения этой проблемы:

  1. Сделать AJAX синхронный вызов (позволяет называть его SJAX).
  2. Реструктурируйте свой код для правильной работы с обратными вызовами.

1. Синхронный AJAX — Не делайте этого !!

Что касается синхронного AJAX, не делайте этого! Ответ Феликса вызывает некоторые веские аргументы в пользу того, почему это плохая идея. Подводя итог, он заморозит браузер пользователя, пока сервер не вернет ответ и не создаст очень плохой пользовательский интерфейс. Вот еще краткое резюме из MDN о том, почему:

XMLHttpRequest поддерживает как синхронную, так и асинхронную связь. В общем, однако, асинхронные запросы должны быть предпочтительнее синхронных запросов по причинам производительности.

Короче говоря, синхронные запросы блокируют выполнение кода … … это может вызвать серьезные проблемы …

Если вы имеете , вы можете передать флаг: Вот как это сделать:

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. Код реструктуризации

Пусть ваша функция принимает обратный вызов. В примере код foo может быть сделан для принятия обратного вызова. Мы сообщим нашему кодексу, как отреагировали , когда foo завершает работу.

Итак:

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

Становится:

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

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

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

Для получения дополнительной информации о том, как выполняется этот вид обратного вызова, проверьте ответ Felix.

Теперь давайте определим сам foo, чтобы действовать соответственно

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

(скрипка)

Теперь мы сделали нашу функцию foo принять действие, которое будет выполняться, когда AJAX завершится успешно, мы можем продолжить это, проверив, не является ли статус ответа не 200 и действует соответственно (создайте обработчик сбоя и т. д.). Эффективное решение нашей проблемы.

Если вам все еще трудно понять это , прочитайте руководство по началу работы AJAX в MDN.

ответ дан ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000 17 August 2018 в 10:05

поделиться

ответ дан eFarzad 17 August 2018 в 10:05

поделиться

Еще один подход к возврату значения из асинхронной функции — передать объект, который сохранит результат от асинхронной функции.

Вот пример того же:

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

Я использую объект result для хранения значения во время асинхронной операции. Это позволяет получить результат даже после асинхронного задания.

Я использую этот подход много. Мне было бы интересно узнать, насколько хорошо этот подход работает, когда задействован результат обратно через последовательные модули.

ответ дан Peter Mortensen 17 August 2018 в 10:05

поделиться

ответ дан Peter Mortensen 6 September 2018 в 07:40

поделиться

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

Похожие вопросы:

  • Remove From My Forums
  • Question

  • User1406973109 posted

    Good day all,

    Please i wrote a jquery ajax get function to get data from sql server database, but the jquery side is always displaying undefined.

    The database side returns a string, i want to display the returned string in a span.

    This is my code, please what i’m i doing wrong

    The script

    <script type="text/javascript">
            $(document).ready(function () {
                showData();
            });
    
            function showData()
            {            
                $.ajax({
                    type: 'GET',
                    url: 'ReceivedData.aspx/GetData',
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (data) {
                        alert(data);
                        $.each(data, function (index, val) {
                            //$('#stockPrices').html(val.StockDetails);
                            document.getElementById("stockPrices").innerHTML = val;
                             //.append(val.StockDetails);
                        });
                    },
                    error: function (response) {
                        alert(response.d);
                    }
                });
                alert("It has ended");
            }
        </script>

    The GetData Function

    [WebMethod()]
            //[ScriptMethod()]
            public static string GetData()
            {
                string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
                string returnedData = "";
                using (var sqlConn = new SqlConnection(strConn))
                {
                    if (sqlConn.State == System.Data.ConnectionState.Closed)
                    {
                        sqlConn.Open();
                    }
    
                    var objCmd = new SqlCommand();
                    objCmd.Connection = sqlConn;
                    objCmd.CommandType = System.Data.CommandType.Text;
                    objCmd.CommandText = "Select Top(1) StockDetails From tbl_Nse ORDER BY PKID DESC";
    
                    SqlDataReader objDr = objCmd.ExecuteReader();
                    if (objDr.HasRows == true)
                    {
                        while (objDr.Read())
                        {
                            returnedData = objDr["StockDetails"].ToString();
                        }
                        return returnedData;
                    }
                    else
                    {
                        returnedData = "";
                        return returnedData;
                    }
                }
            }

    Even when i commented the code and just did a returned an ordinary string, it still brought error as undefined

    Thanks

    Tim

Answers

  • User475983607 posted

    The web method needs a ScriptMethod attribute to allow an HTTP GET.  The default is POST which I recommend.

    [WebMethod()]
    [ScriptMethod(UseHttpGet = true)]
    public static string GetData()
    {
        return "Hello World!";
    }

    AJAX is asynchronous so the line…

     alert("It has ended");

    will always show before the AJAX results.

    The each loop is unnecessary as you are returning a scalar (single) value.  

    success: function (data) {
                        alert(data);
                        $.each(data, function (index, val) {
                            //$('#stockPrices').html(val.StockDetails);
                            document.getElementById("stockPrices").innerHTML = val;
                             //.append(val.StockDetails);
                        });
                    },

    Consider using the .done() and .fail() promises as opposed to success: and error:

    Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

    http://api.jquery.com/jquery.ajax/

    Use execute scalar in the web method rather than a data reader since you are returning a scalar value.  This will reduce lines of code and complexity. 

    https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx

    Lastly, consider using console.log() and debug using developer tools (F12) rather than alert.  console.log() writes to the browser console and will show object models which is helpful when returning complex types.

    Working example that calls the web method above.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AjaxDemo.aspx.cs" Inherits="WebFormsDemo.AjaxDemo" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>AJAX Demo</title>
        <script src="Scripts/jquery-3.1.1.js"></script>
        <script>
            $(document).ready(function () {
                showData();
            });
    
            function showData()
            {            
                $.ajax({
                    type: 'GET',
                    url: 'AjaxDemo.aspx/GetData',
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json'
                }).done(function (data) {
                    console.log(data.d);
                }).fail(function (response) {
                    console.log(response);
                });
            }
           
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
        
        </div>
        </form>
    </body>
    </html>
    
    • Marked as answer by

      Thursday, October 7, 2021 12:00 AM

  • User-1509636757 posted

    Can you test that at your side, since the other aspx to aspx is working.

    No issues with HTML page as well, here is the HTML page code:

    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script src="Scripts/jquery-2.0.0.min.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                showData();
            });
    
            function showData() {
                $.ajax({
                    type: 'GET',
                    url: 'WebForm158.aspx/GetData',
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (data) {
                        alert(data);
                        $.each(data, function (index, val) {
                            document.getElementById("stockPrices").innerHTML = val;
                        });
                    },
                    error: function (response) {
                        alert(response.d);
                    }
                });
                alert("It has ended");
            }
        </script>
    </head>
    <body>
        <label id="stockPrices"></label>
    </body>
    </html>

    and the same code behind WebMethod:

    [WebMethod()]
    [ScriptMethod(UseHttpGet = true)]
    public static string GetData()
    {
        string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
        string returnedData = "";
        using (var sqlConn = new SqlConnection(strConn))
        {
            if (sqlConn.State == System.Data.ConnectionState.Closed)
            {
                sqlConn.Open();
            }
    
            var objCmd = new SqlCommand();
            objCmd.Connection = sqlConn;
            objCmd.CommandType = System.Data.CommandType.Text;
            objCmd.CommandText = "Select Top(1) StockDetails From tbl_Nse ORDER BY PKID DESC";
    
            SqlDataReader objDr = objCmd.ExecuteReader();
            if (objDr.HasRows == true)
            {
                while (objDr.Read())
                {
                    returnedData = objDr["StockDetails"].ToString();
                }
                return returnedData;
            }
            else
            {
                returnedData = "";
                return returnedData;
            }
        }
    }
    • Marked as answer by
      Anonymous
      Thursday, October 7, 2021 12:00 AM

  • User1406973109 posted

    Hi Guys, Thanks so much for your contributions, they have really enlightened me.

    Looking at the Network tab, it clearly shows it an authentication problem, because of this, it was being redirected to the login page.

    So to solve this i practically recreated the project, leaving out the authentication entirely (Not really necessarily), since i wasn’t using them.

    Then it brought a 401 Unauthorized error, that i corrected in the RouteConfig file, in the App_Start folder, by changing

    settings.AutoRedirectMode = RedirectMode.Permanent;

    To:

    settings.AutoRedirectMode = RedirectMode.Off;

    Everything works very fine now.

    Thanks very much

    Tim

    • Marked as answer by
      Anonymous
      Thursday, October 7, 2021 12:00 AM

I have written an Ajax function which works perfectly fine, however, when I try to pass the result of it into another function the result is undefined. Im sure its a very simple solution but I’m new to asynchronous js and Ajax as a whole.

My Ajax call:

function get_message(callback){
	$.ajax({
		type: 'POST',
		url: "reg_username_checker",
		data: {username: username},
		dataType: "text",
		success: function (data){
			callback(data);
		}
	});
}

Function to return the data from the callback:

function test_print_message(message){
	console.log(message);
	return message;
}

and calling the functions: (this is inside another function if that makes a difference)

var a = get_message(test_print_message);
console.log(a);

the console.log inside the test_print_message function works and logs the correct value, however when calling the function and assigning the value to the variable a , console.log(a); doesn’t work and just logs undefined. I have also tried adding async: false to the Ajax query, even though it is discouraged, and that still doesn’t help.

Thanks for any help!


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi,

I am still a learning ajax and jquery but I encounter an error which I dont know how to resolve.

I am currently applying jquery on my webapps but it is displaying undefined when I issue an ajax request

As per my firebug, I see this the value of «entry» as below:

I think I am successful in generating the json response on my spring mvc controller.

but when I call the method entry[‘strFirstName’], it says undefined.

Is there something wrong?

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

And what is entry? Did you do a console.log(entry) and see what it is?

Eric

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Eric,

And what is entry?

I was referring to this.


$.each(data, function(entryIndex, entry){

For each iteration of the each function, I see the json string…

But I am not sure why when I call , I get undefined value.

I check also the json response on my firebug and I see an HTTP status of 200 on the XHR tab and I see the response correctly seen on the json tab

Thanks..

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

You’re getting a string? Not a JavaScript construct? If that’s the case, then of course you can’t reference into it until its been converted to a construct.

If jQuery is not doing it for you, chances are that the JSON coming back from the response is malformed.

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Bear,

I am currently experimenting a json library called json-lib in my spring mvc web apps.

As I check on the firebug console, I saw below images and .

I am currently unsure if the response is really malformed given the images I see on firebug.

I tried another way of parsing my json response but it still results to undefined..

Thanks.

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Eric Pascarello

author

Posts: 15385


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

problem here is you are not returning a JSON object, you are returning an array.

Your output should look like

{ items : [{}, {}, {}] }

that you each loop would be

$.each(data.items, … );

Eric

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi,

I finally got my first json attempt using below code as per your advise.

Thanks to you…

But doing this, I have several questions that I want to confirm. Hope you’ll still be patient on me.

1. Why is it that I get undefined value when I replace this code with this

The this keyword refers to the current object as I checked with the firebug console.

2. Libraries such as GSON/JSON Lib return a stringify representation of my java objects and does not really return a javascript construct? It is upto you to use the eval() function to convert this to a javascript construct. Is my understanding correct?

3. In the jquery api, I notice the [] (square bracket), does it signifies that this returns an array.

Sorry for the many questions, I just jump out into jquery and been trying so many things at once to learn about this library.

I can now edit my spring mvc app to add ajax support.

Thanks a lot.

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Bear Bibeault

Sheriff

Posts: 67695

Mac
Mac OS X
IntelliJ IDE
jQuery
TypeScript
Java
iOS


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

mark reyes wrote:1. Why is it that I get undefined value when I replace this code with this

The this keyword refers to the current object as I checked with the firebug console.

It does not. The

this

keyword always refers to the function context (there’s no such things as a «current» object). And

$(this)

is a jQuery wrapped set that contains the referenced instance. There’s no such field as

strFirstName

defined by jQuery som I’m clueless as to what you are actually trying to do.

2. Libraries such as GSON/JSON Lib return a stringify representation of my java objects and does not really return a javascript construct? It is upto you to use the eval() function to convert this to a javascript construct. Is my understanding correct?

It returns JSON, an interchange format. Something needs to interpret it to turn it into a JavaScript construct. $.getJSON will do it for you if its valid.

3. In the jquery api, I notice the [] (square bracket), does it signifies that this returns an array.

No. That indicates optionality.

If only someone had written a book on jQuery that would make all of this clear….

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Bear,

I missed reading this post.

You’re getting a string? Not a JavaScript construct? If that’s the case, then of course you can’t reference into it until its been converted to a construct.

If jQuery is not doing it for you, chances are that the JSON coming back from the response is malformed.

I think I am making a mistake in creating the response. Kindly have a look at how I do it and point out if something is wrong please..

In my Spring MVC, I am doing below procedure

I think the response object does get pass at the client side but the call to $.getJSON fails and cannot convert it to a construct.

Do you think this is the case here?

This is what happen when I call below in my jquery code

It returns undefined: But as I have checked the XHR tab on my firebug console, I did see the JSON response

Sorry for the length post.. I am just totally confused on how to do it. Most of the ajax code that I see uses PHP but I dont know PHP. I am beginning to think that my response is really malformed.

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Bear Bibeault

Sheriff

Posts: 67695

Mac
Mac OS X
IntelliJ IDE
jQuery
TypeScript
Java
iOS


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Sorry I will not look at screen shots rather than posted code.

But the only thing that is of interest is the body of the response. Have you used a tool such as Firebug to inspect it and make sure that it’s what you expect? And something that getJson() will handle?

Eric Pascarello

author

Posts: 15385


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

rows

is a string, not a object. Look at the response closely and you will see why.

Eric

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Bear and Eric,

I reconfigured my spring json builder and have added «()» before I sent out the response

I change back my code again and used eval on the string response using below code:

I checked on firebug console and see the value of the response body as:

The HTML markup was successfully added.

I have some assumption that I would like to confirm though:

1. I needed the eval function because the call to $.getJSON does not results to a valid JSON Format.

This brings me back to my original question GSON would return a ‘stringify’ representation of my java object and its up to you to build a valid javascript construct at the client side.

May I know what I need to do at the server side so that I wont need the eval function at the client side? I see a lot of PHP-serverside codes, and I cannot see the eval function being used at the jquery side

2. I am returning one JSON object and not an array, I needed the parenthesis because of what is stated in this URL

It states:

Note The extra parentheses are used make eval unconditionally treat the source input like an expression. This is especially important for objects. If you try to call eval with a string containing JSON text that defines an object, such as the string «{}» (meaning an empty object), then it simply returns undefined as the parsed result. The parentheses force the JavaScript parser to see the top-level curly braces as the literal notation for an Object instance rather than, say, curly braces defining a statement block. Incidentally, the same problem does not occur if the top-level item is an array, as in eval(«[1,2,3]»). For sake of uniformity, however, JSON text should always be surrounded with parentheses prior to calling eval so that there is no ambiguity about how to interpret the source.

Sorry for taking so much of your time but I think I am learning things..

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Bear Bibeault

Sheriff

Posts: 67695

Mac
Mac OS X
IntelliJ IDE
jQuery
TypeScript
Java
iOS


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

What’s with the extra parens? That may be what’s fouling up getJson(). If you’re going to do the eval() yourself (not recommended), don’t use getJson()!

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Bear,

If I dont use an eval on this code and just do it like this

It is evaluated as undefined — undefined. The HTML Mark up would not result in my name being appended into it but rather the word undefined.

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Bear Bibeault

Sheriff

Posts: 67695

Mac
Mac OS X
IntelliJ IDE
jQuery
TypeScript
Java
iOS


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

If you want to fix this, then this needs to cut to the chase. What is being returned as the response that is not being correctly evaluated?

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Bear,

When I execute this code

But when I try to execute with this statement, I was thinking that $.getJSON already made the conversion into a JSON construct already

It prints undefined.

As what Eric mentioned above, data.rows is a string so I need to add an eval() method prior to calling the object property (e.g. data.rows.strFirstName)

But as what you are saying, If you’re going to do the eval() yourself (not recommended), don’t use getJson()!

This gets me confused actually.

I checked on the xhr tab on my firebug and I see this one printed on the response.

There’s a bunch of «» in the response.

I am not sure if this is what you are looking though.

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Bear Bibeault

Sheriff

Posts: 67695

Mac
Mac OS X
IntelliJ IDE
jQuery
TypeScript
Java
iOS


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

The JSON that is being returned defines rows as a string. It will not evaluate to a structure. You need to fix the JSON, not hack the page.

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Bear,

The JSON that is being returned defines rows as a string. It will not evaluate to a structure. You need to fix the JSON, not hack the page

Sorry, I dont have an idea on how to fix the JSON. Can you give me a hint where to do the change?

Is it in my Spring controller?

Pardon me for dragging your time into this so much…

Thanks…

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

Bear Bibeault

Sheriff

Posts: 67695

Mac
Mac OS X
IntelliJ IDE
jQuery
TypeScript
Java
iOS


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Wherever the JSON is being generated on the server.

The fact that:

«{«strUserID»:»»,»strPassword»:»1″,»strFirstName»:»Mark»,»strLastName»:»Reyes»,»strMI»:»»}»

is in the outer quotes, makes it a string.

Mark Reyes

Ranch Hand

Posts: 426


posted 12 years ago

  • Mark post as helpful


  • send pies

    Number of slices to send:

    Optional ‘thank-you’ note:



  • Quote
  • Report post to moderator

Hi Eric and Bear,

For some reason that I dont know, when I write the json response using the GSON API in my Spring MVC controller, the call to $.getJSON cannot convert the response to a valid javascript construct

I revert back to using the JSON-LIB JSON Library and it was able to construct the correct javascript construct without using the eval option.

Kudos to both of you. I did learn a lot doing this simple exercise.

Thanks.

Sean Clark —> I love this place!!!

Me ——> I definitely love this place!!!

NOTE: The original premise of this post was WRONG. I talked about NULL values, but demonstrated «undefined» values. This only applies to Undefined values!! Thanks to Justice for this critical catch!!

When you trigger an AJAX request in jQuery, you have the option to supply a «data» object with the request. This data object contains a collection of key-value pairs that get posted as individual form (or url) parameters. There is a small feature of the AJAX request model that took me a little while to get used to; but, now that I understand it, I completely love to use it. What I’m referring to is the fact that Undefined values are not posted during an AJAX request.

To demonstrate what I’m talking about, take a look at the following jQuery page:

<!DOCTYPE html>
<html>
<head>
	<title>Undfined Values And AJAX Requests</title>
	<script type="text/javascript" src="../jquery-1.4.4.js"></script>
</head>
<body>

	<h1>
		Undefined Values And AJAX Requests
	</h1>

	<form>

		<input type="submit" value="Post AJAX" />

	</form>

	<div id="results" style="margin-top: 30px ;">
		<!--- This is where we'll post the AJAX response. --->
	</div>


	<!--- ------------------------------------------------- --->
	<!--- ------------------------------------------------- --->


	<script type="text/javascript">

		// Create an object to hold a number of values that we are
		// going to be posting to the AJAX request handler.
		var clientSideData = {
			a: 1,
			b: 2,
			z: 3
		};


		// Now, bind to the form to trap the submission and handle it
		// via an AJAX request.
		$( "form" ).submit(
			function( event ){

				// Prevent the default form submission.
				event.preventDefault();

				// Now, post varaibles to the request handler.
				//
				// NOTE: As we do this, some of the values we pass
				// will exist, some will not.
				$.ajax({
					type: "post",
					url: "./handler.cfm",
					data: {
						a: clientSideData.a,
						b: clientSideData.b,
						c: clientSideData.c,
						x: clientSideData.x,
						y: clientSideData.y,
						z: clientSideData.z
					},
					dataType: "html",
					success: function( html ){

						// Dump the response into the page.
						$( "#results" ).html( html );

					}
				});

			}
		);

	</script>

</body>
</html>

At the top of my Javascript, you’ll notice that I am defining a client-side data structure with a few properties. Then, when I go to trigger my AJAX request, you can see that I am posting both defined (a, b, z) and undefined (c, x, y) properties from said data structure. Now, rather than passing c, x, and y as Undefined values or some sort of empty string or falsey value, jQuery simply ignores them.

To illustrate this, my AJAX request handler — handler.cfm — echoes its own FORM scope:

handler.cfm

<!--- Set the response type. --->
<cfcontent type="text/html" />

<!---
	Simply CFDump out the FORM post values so that we show the
	client which form variables were passed with the AJAX request.
--->
<cfdump
	var="#form#"
	label="Form Post"
	/>

And, when we make the AJAX request, we can clearly see that our undefined values are neither posted to the handler nor echoed back in the response:

UNDEFINED Values Do Not Get Passed Along With A jQuery AJAX Request.

At first, this might feel weird; after all, if you tell jQuery to post something, shouldn’t it at least try to post the Key? Once you get used to this concept, however, it becomes really nice to work with. Take, for example, something like the Javascript Geolocation API. When you work with geolocation and the browser, the user has the opportunity to deny geolocation access; and, even if access is granted, there is a chance that the browser won’t be able to determine the proper location.

This means that if you need to post geolocation information back to the server, there’s a chance that no location information will be available. You could use some complex client-side logic to dynamically build your AJAX data object based on the information that is available; or, you could just post NULL values and live hassle-free.

// Default the location to a undefined coordinate set. This way, we
// have a constant data structure.
var location = {};


// -- Get geolocation... code not shown. Will update the
// -- the location data struct once latitude and longitude
// -- become available.


// Post location to the server. It may be UNDEFINED.
$.ajax({
	...
	data: {
		latitude: location.latitude,
		longitude: location.longitude
	}
	...
});

Here, you can see that the location information starts off as undefined coordinate values that may or may not be updated over time. Then, when we go to post the location, we simply post the local coordinates, not taking into account whether or not they are defined. We leave the «checking» up to jQuery and allow our client-side code to remain as simple as possible.

I know this is just a tiny feature of the jQuery AJAX request model; but, it is a feature that I have come to really like. And, as your client-side code starts to become more robust, the chances that you’ll post Undefined values to the server definitely go up. It’s nice to know that jQuery doesn’t require us to worry about the insignificant details.

Want to use code from this post?
Check out the license.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!

Понравилась статья? Поделить с друзьями: