4

I have an input field. Whenever there's change in the text in the input field, I make an ajax call to process.php

I need to handle all the responses. But some responses come early, whereas some come late, depending on the input. So the order of responses is not same as order of making ajax calls.

So right now I'm doing it by setting async: false

But I don't want the client side to be stuck due to async: false

$("#text_input").on("input", function() {

    var password = $("#text_input").val();
    var length = password.length;

    $.ajax({
        url: "process.php",
        type: "POST",
        async: false,
        data: {
            password: $(this).val()
        }
    }).done(function (data) {

        console.log(data);

        console.log(password + " : " + length);

    }).fail(function( jqXHR, textStatus, errorThrown ) {
        alert( "Request failed: " + textStatus + " , " + errorThrown );
    });

});

I tried looking in promises, but did not understand whether it can be applied here.

How can I execute responses in order?

user5155835
  • 4,392
  • 4
  • 53
  • 97
  • Generators could help you - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Generator – Belmin Bedak Jun 27 '17 at 08:52
  • Use jQuery for combining Promises. Check here some useful tutorial: http://www.htmlgoodies.com/beyond/javascript/making-promises-with-jquery-deferred.html – Giacomo Paita Jun 27 '17 at 08:53
  • @BelminBedak Looking into it. Please can you tell how they would apply here? – user5155835 Jun 27 '17 at 08:53
  • this might help you. https://stackoverflow.com/questions/6685249/jquery-performing-synchronous-ajax-requests – Dheeraj Kumar Jun 27 '17 at 08:54
  • If you have any way of moving whatever it is you do server side to client side, then that would be the way to go. That would make it real time. – Repo Jun 27 '17 at 09:08

3 Answers3

2

The problem with async is exactly that, that is asynchronous, that means that the code runs without waiting to finish. Therefore all your requests go to the server and once they start returning your code catches them and executes them.

If you want to handle them in order, you will need to build a queue and the code to handle the queue.

You should then assign an ordered number to all your requests which should then come in the response (so you know the proper order of the response).

Then you can add the response to the queue, and call a method which processes the queue, but that method only processes the queue in order, meaning that it only processes responses starting from 0, 1, 2, 3 etc... so if in the queue there is a result 5 and not a result 0, the queue won't be processed, the queue will be processed only if result 0 is there and so on...

Here is an example code, I haven't tested it but should work or at least should give you an idea on how to start :)

var currentOrder = 0;
var queue = [];

function processQueue() {
  // Sort the queue
  queue.sort(function(a, b) {
    var aOrder = a.order;
    var bOrder = b.order;

    if (aOrder < bOrder) {
      return -1;
    }
    if (aOrder > bOrder) {
      return 1;
    }
    // Order is equal (this shouldn't happen)
    return 0;
  });

  if (queue[0].order === currentOrder) {
    doSomething(data);
    queue.splice(0, 1); // Remove the first item from the queue as it's already processed
    currentOrder++;
    processQueue(); // Process the queue again
  }
}

// Do something with the data
function doSomething(data) {
  console.log(data);
}

$('#text_input').on('input', function() {
  $.ajax({
    url: 'process.php?order=' + order, // We send the order to the backend so it can be returned in the response
    type: 'POST',
    data: {
      password: $(this).val()
    }
  }).done(function(data) {
    // Data should contain the order somewhere, let's say for example it's a json and it's inside data.order
    queue.push(data);
    processQueue();
  });
});
amilete
  • 106
  • 3
1

Assuming that you are only interested in the results of the latest ajax call, you can assign the value returned from the $.ajax call - a jqXHR object - to a variable and then abort the request when a new one is fired.

Something like:

var request = null;

$("#password_input").on("input", function() {
    var password = $("#password_input").val();
    var length = password.length;

    // you can also check the type of the variable, etc.
    if (request) {
        request.abort();
    }

    request = $.ajax({
        url: "process.php",
        type: "POST",
        ...
jeroen
  • 91,079
  • 21
  • 114
  • 132
  • I want to make request for every change in input and handle ALL the responses. Will I be able to achieve this by your solution? – user5155835 Jun 27 '17 at 08:58
  • @user5155835 Can I ask why? That doesn't seem to make a lot of sense when you are when you are monitoring the changes on a text input. At least that is what it looks like to me... – jeroen Jun 27 '17 at 09:02
  • @user5155835 And no, when a new request is fired before a previous on has finished, the previous one will be cancelled. Great for search-as-you-type :-) – jeroen Jun 27 '17 at 09:03
  • @user5155835 I don't think so, the only response that the user is interested in, is the one that appears when he or she finishes typing. – jeroen Jun 27 '17 at 09:06
  • Suppose user types x, I give suggestion y. I see whether user types my suggestion. So if he types y, I record it. Then for xy, I give suggestion z. And see whether user types z, and record it. And so on. At the end I want to see how many suggestions did the user type. That's why I need to make every request and handle every response. – user5155835 Jun 27 '17 at 09:09
  • So as per your first line of answer: "Assuming that you are only interested in the results of the latest ajax call" This is not true for my case – user5155835 Jun 27 '17 at 09:14
  • @user5155835 I stil think it is :-) The requests are only aborted when the input is changed while the previous request is still processing. How are you providing feedback to the user? There's not much point in flashing content the user cannot see anyway. You should probably just try it. – jeroen Jun 27 '17 at 09:17
0

Why not use setTimeout function to whenever they press some letter on your input field. you can do it just like this:

setTimeout(function(){
     $.ajax({
       url: "process.php",
       type: "POST",
       data: {
           password: $(this).val()
       }
   }).done(function (data) {

       console.log(data);

       console.log(password + " : " + length);

   }).fail(function( jqXHR, textStatus, errorThrown ) {
       alert( "Request failed: " + textStatus + " , " + errorThrown );
   });
}, 1000);

This is to setTimeout once the press on your input field and wait 1sec then when finished type on the input field it will generate the ajax after 1sec.