Matteo
Matteo

Reputation: 8142

Javascript wait for ajax success before code execution

I'm trying to implement the following scenario on my web page:

  1. A user visits a page (note that users have a unique ID)
  2. The user must perform a task and then press the next button
  3. When the button is pressed, I look up in a database to see if it was the user's first visit
  4. If it was he must wait 60 seconds before he can press the button so I alert him

I checked for solutions of similar synchronization problems:

but couldn't really adapt them to my case.

The following snippet gets executed every time the user presses the next button.

    // get timing for instruction reading
    var currentTime = new Date().getTime();
    totalTime = currentTime - startTime;
    console.debug("Time: " + totalTime);
    if (flag_instructions_pressed == false){
        $.ajax({
            url: "/IsNewUser/",
            type: "POST",
            contentType: "application/json",
            data: JSON.stringify({
                "_user_id": _user_id,
            }),
            dataType: "text",
            success: function( returned_data ) {
                _user_exp = parseInt(returned_data);
                flag_instructions_pressed = true;
            }
        });
    }

    if ( totalTime < 60000 && _user_exp == 0) {
        alert("You have to wait 60 seconds");
        return;
    }

I have the following problem:

Even if a user has visited the page multiple times he will still be shown the alert since the if statement is executed before the success function from the ajax request.

How do I solve it?

NOTE 1: I cannot simply move the if statement into the success function because that should still be executed even after the flag_instructions_pressed is set to true. flag_instructions_pressed is just a flag initialized to false that gets set to true after the ajax request is performed. This prevents the request from happening again when the code is executed a second time.

NOTE 2: Obviously if I put an alert (or simply a timeout) before the if statement, everything works fine. But I think it is bad programming practice and would like to learn how to deal with this type of synchronization problems.

Upvotes: 3

Views: 1723

Answers (2)

badjuju
badjuju

Reputation: 11

How about turning the if statement into a function:

function testTime() { 
  if ( totalTime < 60000 && _user_exp == 0) {
    alert("You have to wait 60 seconds");
    return;
  }
}

And then make the other if statement into an if/else, calling this function both in the else block (flag_instructions_pressed == true) and in the success function of the ajax call (flag_instructions_pressed == false):

if (flag_instructions_pressed == false){
    $.ajax({
        url: "/IsNewUser/",
        type: "POST",
        contentType: "application/json",
        data: JSON.stringify({
            "_user_id": _user_id,
        }),
        dataType: "text",
        success: function( returned_data ) {
            _user_exp = parseInt(returned_data);
            flag_instructions_pressed = true;
            testTime();
        }
    });
} else {
  testTime();
}

Upvotes: 1

JLRishe
JLRishe

Reputation: 101738

One solution to this is to make use of promises. They serve as a placeholder for a future value and you can "check their future value" multiple times:

var newUserCheck;

function nextButtonHandler() {
    // get timing for instruction reading
    var currentTime = new Date().getTime();
    totalTime = currentTime - startTime;
    console.debug("Time: " + totalTime);

    if (!newUserCheck) {
        newUserCheck = $.ajax({
            url: "/IsNewUser/",
            type: "POST",
            contentType: "application/json",
            data: JSON.stringify({
                "_user_id": _user_id,
            }),
            dataType: "text"
        }).then(function ( returned_data ) {
           _user_exp = parseInt(returned_data);
           return _user_exp;
        });
    }

    newUserCheck.then(function (user_exp) {
        if ( totalTime < 60000 && user_exp === 0 ) {
            alert("You have to wait 60 seconds");
            return;
        }

        // otherwise, complete the "next button procedure" here
    });
}

Upvotes: 1

Related Questions