pullidea-dev
pullidea-dev

Reputation: 1803

javascript async await not waiting

Here are the functions I have.

async function check_saved_url() {
  $.get("https://ipinfo.io/json", function (response) {
    current_ip = response.ip;
    location_here = response.country;
    
    var ajax_get_url_prefix = base_url + 'getDomain.php?ip=';
    var key_ip = current_ip + '@@@' + domain_permanent;
    var url = ajax_get_url_prefix + key_ip;
    
    $.get(url, function(data, status) {
      console.log("Data: " + data + "\nStatus: " + status);
      if (data.includes('0 results')) {
        return 'unknown';
      } else {
        return data;
      }
    });
  }, "jsonp");
}

const func1 = async() => {
  return await check_saved_url();
}

const func2 = async() => {
  let domain_preference = '';
  domain_preference = await func1();
  console.log("domain_preference: ",domain_preference);
}
func2();

This method is from this answer.

As you can see, there are two jquery ajax to get data from server.

The problem is, the func1 and func2 never waits until check_saved_url returns value.

This is what I see in console.

enter image description here

The top red line is the output of func2, which must wait until check_saved_url runs, whose result is the following 2 circles.

I am not sure why this persists to happen and hours of copying answers from everywhere didn't help me.

Upvotes: 0

Views: 1786

Answers (5)

Ben Aston
Ben Aston

Reputation: 55739

You probably need to develop your understanding of promises and how async JavaScript works a little.

If you have to use jQuery, you could promisify the jQuery $.ajax method (which appears to use a very old version of the promise API?), and then use that with modern JS constructs like async/await.

const pGet = (url, dataType = 'jsonp') => 
  new Promise((success, error) => $.ajax({url, dataType, success, error}))
   
const IP_URL = 'https://ipinfo.io/json'
const PREFERENCE_URL_PREFIX = 'https://www.example.com/getDomain.php?ip='

const go = async () => {
  try {
    const { ip } = await pGet(IP_URL)
    const preference = await pGet(`${PREFERENCE_URL_PREFIX}${ip}`)
    //do something with the preference
  } catch(err) {
    // handle errors
  }
}

go()
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

If you don't have to use jQuery, I'd avoid it and use the fetch API provided by modern host environments.

const IP_URL = 'https://ipinfo.io/json'
const PREFERENCE_URL_PREFIX = 'https://www.example.com/getDomain.php?ip='

const go = async () => {
  try {
    const { ip } = await (await fetch(IP_URL)).json()
    const preference = await fetch(`${PREFERENCE_URL_PREFIX}${ip}`)
    //do something with the preference
  } catch(err) {
    // handle errors
  }
}

go()
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Upvotes: 2

Newbie
Newbie

Reputation: 4829

There is no promise returned by check_saved_url nor is $.get returning a promise. You need to wrap it all in a promise

async function check_saved_url() {
    return new Promise((resolve, reject) => {
        $.get("https://ipinfo.io/json", function (response) {
            current_ip = response.ip;
            location_here = response.country;

            var ajax_get_url_prefix = base_url + 'getDomain.php?ip=';
            var key_ip = current_ip + '@@@' + domain_permanent;
            var url = ajax_get_url_prefix + key_ip;

            $.get(url, function(data, status) {
                console.log("Data: " + data + "\nStatus: " + status);
                if (data.includes('0 results')) {
                    resolve('unknown');
                } else {
                    resolve(data);
                }
            })
                .fail(reject);
        }, "jsonp")
            .fail(reject);
    })
}

Clean the code

To have a cleaner and reusable code you can wrap $.get in a Promise

async function async_get(url) {
    return new Promise((resolve, reject) => {
        const jqxhr = $.get(url);
        jqxhr.done(() => resolve({ json: jqxhr.responseJSON, status: jqxhr.status }));
        jqxhr.fail(() => reject(jqxhr));
    })
}

async function check_saved_url() {
    const { json: response } = await async_get("https://ipinfo.io/json");
    current_ip = response.ip;
    location_here = response.country;
    var ajax_get_url_prefix = base_url + 'getDomain.php?ip=';
    var key_ip = current_ip + '@@@' + domain_permanent;
    var url = ajax_get_url_prefix + key_ip;

    const { json: data, status } = await $.get(url);
    console.log("Data: " + data + "\nStatus: " + status);
    return data.includes('0 results') ? 'unknown' : data;
}

Upvotes: 1

Alok Prakash
Alok Prakash

Reputation: 331

I will suggest you to use fetch API check_saved_url(). It return promise. You can read more about it here. https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Code will go like this :

async function check_saved_url() {
    let connect = await fetch("https://ipinfo.io/json")
    let response = await connect.json()
    current_ip = response.ip;
    location_here = response.country;
    
    var ajax_get_url_prefix = base_url + 'getDomain.php?ip=';
    var key_ip = current_ip + '@@@' + domain_permanent;
    var url = ajax_get_url_prefix + key_ip;
      
    //   $.get(url, function(data, status) {
    //     console.log("Data: " + data + "\nStatus: " + status);
    //     if (data.includes('0 results')) {
    //       return 'unknown';
    //     } else {
    //       return data;
    //     }
    //   });
    // }, "jsonp");
  }

Upvotes: 0

Rojo
Rojo

Reputation: 2869

You need to return a Promise from check_saved_url. Inside of the Promise, you then need to use resolve to replace return. You can also use reject(new Error("error")) if there was an error.

async function check_saved_url() {
  return new Promise((resolve, reject) => {
    $.get("https://ipinfo.io/json", function (response) {
      current_ip = response.ip;
      location_here = response.country;

      var ajax_get_url_prefix = base_url + 'getDomain.php?ip=';
      var key_ip = current_ip + '@@@' + domain_permanent;
      var url = ajax_get_url_prefix + key_ip;

      $.get(url, function(data, status) {
        console.log("Data: " + data + "\nStatus: " + status);
        if (data.includes('0 results')) {
          // Instead of return, use resolve()
          //return 'unknown'; 
          resolve('unknown');
          // You can also pass an error with `reject(new Error("error"))`
        } else {
          // Instead of return, use resolve()
          //return data; 
          resolve(data);
        }
      });
    }, "jsonp");
  });
}

const func1 = async() => {
  return await check_saved_url();
}

const func2 = async() => {
  let domain_preference = '';
  domain_preference = await func1();
  console.log("domain_preference: ",domain_preference);
}
func2();

You can read more about promises on MDN

Upvotes: 1

Krokodil
Krokodil

Reputation: 1470

Your function check_saved_url does not return a promise - this is why await is not working for it.

The solution would be to return a promise in check_saved_url.

Suppose I have a function create_promise which I want to await (this mimics your 'get' request):

function create_promise() {
  return new Promise(resolve => {
    setTimeout(() => resolve("Done!"), 500);
  });
}


const func1 = async() => {
  const result = await create_promise();
  return result + " <- result";
};

func1().then(console.log);

Upvotes: 0

Related Questions