Using async / await with $.ajax

Viewed 2232

This is my first attempt to utilize asynchronous javascript. I've tried hooking up every incarnation of promises that I can find, but have not been able to write them successfully to get my string to return (i.e. $.Deferred, async/await, Promise, callbacks, relying on .done). async:false as an ajax variable works, but I'm trying to avoid settling for what I understand is bad practice. I would love to use async/await because it is so concise, but at this point I'm up for anything that works. I have a suspicion that I'm trying to utilize the $.ajax return in an incorrect manner.

Much appreciation for a working return of the string wholename (a randomized first and last name), examples of a few versions for my own education even more appreciated!

function Actor(gender, name) {
if (gender == "" || gender == undefined) {this.gender = "female";} else this.gender = gender;        
if (name == "" || name == undefined) {this.name = makeName(this.gender);} else this.name = name;
}

function getPromiseName(sex) {
    return promise = $.ajax({
        type: "GET",
        url: "TMxml.xml",
        dataType: "xml"//,
        //async: false   //this works for returns, but is apparently bad practice
    }); 
}

function makeName(sex) {
    var fnames = [];
    var lnames = [];

    var thexml = getPromiseName(sex);

    thexml.done(function(xml) {
        if (sex == "male") {
            $(xml).find('malename').children().each(function(){
                fnames.push($(this).text());
            });
        }
        if (sex == "female") {
            $(xml).find('femalename').children().each(function(){
                fnames.push($(this).text());
            });
        }
        $(xml).find('lastname').children().each(function(){
                lnames.push($(this).text());
            });

        wholename = fnames[Math.floor(Math.random() * fnames.length)] + " " + lnames[Math.floor(Math.random() * lnames.length)];
        alert("wholename = " + wholename); //successfully alerts a randomized name
        return wholename;  //but returns undefined, or [object Promise] when using async/await
    });
}
2 Answers

Here's what I would suggest. This is test data, so the names don't make sense, but of course all you'd have to do is change the url, the getRandomName function and the doStuffWithActor function based on your code above. (As you can see, I would recommend keeping the fetching logic and the actor initialization logic as separate as possible :)

class Actor {
  constructor(name, gender) {
    this.name = name;
    this.gender = gender;
  }
}

Array.prototype.sample = function () {
  if (!this.length) return null;
  const randIdx = Math.floor(Math.random() * this.length);
  return this[randIdx];
};

const createActor = async (url, name, gender, callback) => {
  gender = gender || 'female';
  if (!name) {
    const response = await fetch(url);
    const data = await response.text();
    name = getRandomName(data, gender);
  }
  const actor = new Actor(name, gender);
  if (callback) callback(actor);
};

const getRandomName = (xmlData, gender) => {
  const names = xmlData.split(/\s+/);
  const femaleNames = names.slice(0, names.length / 2);
  const maleNames = names.slice(names.length / 2);
  return gender === 'female' ? femaleNames.sample() : maleNames.sample();
};

const doStuffWithActor = (actor) => {
  console.log('Actor name:', actor.name);
  console.log('Actor gender:', actor.gender);
  console.log('\n');
};

createActor('https://httpbin.org/xml', '', '', doStuffWithActor);
createActor('https://httpbin.org/xml', '', 'male', doStuffWithActor);

You're doing it wrong. You must understand that when you work with async mode, you must use callback function to trigger the function that you want.

if you want manualy find out was sended ajax successfull, you must loop it's status with timer and check the success status - that is not recomended.

The reason that your code is working in sync mode is that, the whole javascript freezes until message is responded - that is not recomended also =)

Working ajax function:

function SendAjax($url_mode, $data_serialize, $print_container, $callback_function) {
        $options = {
            type: "GET",
            url: $url_mode,
            data: $data_serialize,
            dataType: "xml",
            success: function (msg) {
                if ($print_container !== '') {
                    $print_container.html(msg);
                }
                if (typeof $callback_function !== "undefined") {
                    $callback_function(msg);
                }
            },
            error: function (xhr, str) {
                alert('Error: ' + xhr.responseCode);
            }
        };
        $.ajax($options);
    }

Calling SendAjax function:

$(document).delegate(".btn-grid", "click", function () {
    SendAjax("TMxml.xml", "?any_key=true", $(".print-container-if-needed-or-set-null"), $Callback_function_like_your_makeName_function);
});
Related