Home > Software design >  .then() doesn't wait till async function resolves promise?
.then() doesn't wait till async function resolves promise?

Time:07-31

I have two functions. First contains jQuery.get().done() and it's return value is inside done() callback function, as showed below. (I have no idea if using jQuery matters here)

I may not be understanding something, but my functions looks similar to those in first w3 example: https://www.w3schools.com/js/js_async.asp

async function A(){     
  jQuery.get("example.com").done(function(result){
    if (result.indexOf("Example")){
      console.log("sucess");
      return 1;
    } else {
      console.log("Fail");
      return -1;
    }
  })
}

function B(){
  A().then(function(result){
    console.log("Res:"   result);
  })
}

B();

But the output is:

Res:undefined
   // here some time passes for A() to complete.
succes

So I can't understand why .then() doesn't wait for function A() to complete and resolve promise, but instead it acts immediately while result is not defined yet ?

CodePudding user response:

This is much better written using actual promises (which jQuery supports) and await as follows:

async function A() {
    const result = await jQuery.get("example.com");
    if (result.indexOf("Example") !== -1) {
        console.log("sucess");
        return 1;
    } else {
        console.log("Fail");
        return -1;
    }
}

Notes:

  1. Stop using jQuery's .done(). It's non-standard. Use .then() or await.
  2. Don't mix await with .done() or with .then(). Use one model or the other.
  3. There's no need for the res intermediate variable. When you get rid of the .done(), you can just return the value directly.
  4. Note, .indexOf() does not return a boolean. It returns -1 if not found and an index of the position if found. Best not to treat its return value as a boolean.

CodePudding user response:

This isn't really a jQuery thing in particular. It's just async JS in general. I'm not sure you really need the .done() part at all since you're using promises.

But anyway, you have two basic problems.

  1. You need to return something inside of function A, not inside .done(). So you can return jQuery.get().

  2. In function B, you want to wait for function A to complete before hitting the .then() block. That means function B is also async. (In the simple example below you can omit the async keyword on function A.) You need to declare function B as async and then await the completion of function A.

 

function A() {
  return jQuery.get("example.com").done(function(result) {
    if (result.indexOf("Example")) {
      console.log("sucess", result);
    } else {
      console.log("Fail", result);
    }
  });
}

async function B() {
  await A().then(function(result) {
    console.log("Res:");
    // moved to a separate console log, otherwise dev tools might print
    // a lot of [objectObject] instead of the actual result
    console.log(result);
  })
}

B();

If you want to do other stuff inside of function A and then eventually return the result, you can play around with something more like

async function A() {
  const response = await jQuery.get('example.com');
  // more stuff…
  return response;
}

CodePudding user response:

I fixed it by moving return statement outside from the .done(function(){}) and by adding await before jQuery chain. And instead of returning value inside that callback function, now I only pass there value to variable, which is later returned outside of that callback function.

async function A(){     
 let res = 0; 
  await jQuery.get("example.com").done(function(result){ //await was added
    if (result.indexOf("Example")){
      console.log("sucess");
      res = 1; // value is passed to variable, which is returned as result outside this callback function
    } else {
      console.log("Fail");
      res = -1;
    }
  })
  return res; // return statement is outside the callback function
}

function B(){
  A().then(function(result){
    console.log("Res:"   result);
  })
}

B();

I guess the problem was, as @cjl750's answer says, that return statement inside the callback function isn't "seen" as a "true return statement" of that function. So function B() probably saw function A() as a function, which doesn't return anything.


EDIT

I've rewritten the code using $.Deferred() object. It's probably better now. Await is now moved to function B(), it doesn't wait for jQuery chain anymore.

function A(){     
 var dfd = $.Deferred();
 jQuery.get("google.com").then(function(result){ 
    if (result.indexOf("Example")){
      console.log("sucess");
      dfd.resolve(1); 
    } else {
      console.log("Fail");
      dfd.resolve(-1); 
    }
  })
  return dfd.promise();
}

async function B(){
  await A().then(function(result){
    console.log("Res:"   result);
  })
}

B();
  • Related