1

I have a simple chat done with long polling. The chat has 2 rows of conversations (or more). Each row has a unique id and a number of messages to show. When I click on the first line, to show the messages of this conversation, I start an ajax, and it keeps persisting inside a loop in the serverside. However, when I click on the second line, I need to end the previous ajax and start a new one.

I tried some options like the ones below, but I did not find a solution.

$('li.chat-conversation').on('click', function(){
var requestRunning = true;
var xhr;
var id = $(this).attr('data-conversation-id');

var ajaxOpt = {...};

var fn = function(){
    xhr = $.ajax(ajaxOpt);
    if(requestRunning){
        xhr.abort();
        requestRunning = false;
    }
};
var interval = setInterval(fn, 2000);
});

Can anyone help me figure out a logic for this?
Note: setInterval is for example only.

AD Henrique
  • 186
  • 2
  • 13
  • 3
    Possible duplicate of [Abort Ajax requests using jQuery](http://stackoverflow.com/questions/446594/abort-ajax-requests-using-jquery) – merlin2011 Dec 29 '16 at 20:55
  • 1
    Why not just check the `xhr.readystate` value and if it isn't `4`, abort the request? Keeping track of active requests with your own Boolean flag can easily get out of sync. That's why we have the `readystate` property in the first place. – Scott Marcus Dec 29 '16 at 20:59
  • @ScottMarcus But I need a requisition to remain active. Abort only when I click on another line. With the readstate is it possible? – AD Henrique Dec 29 '16 at 21:07
  • @num8er I get it. But I do not want to abort the request that has already reached the server. I wanted to cancel only, (and after returning from the server) if I click on another line – AD Henrique Dec 29 '16 at 21:10
  • @ADHenrique By having all this code in the `click` event handler, the abort will only happen when a line gets clicked and a request is already active. – Scott Marcus Dec 29 '16 at 21:12
  • why to keep hope in low level things like `readystate` when jquery has all stuff to trigger function when it's: `success`, `error`, `complete` ? – num8er Dec 29 '16 at 21:20
  • @ADHenrique Can you clarify. If the response has already returned from the server, then there isn't anything to cancel - the operation is complete at that point. So, what exactly do you need to happen if a click has occurred, which caused a complete AJAX call to be made and then another click occurs? – Scott Marcus Dec 29 '16 at 21:20
  • @num8er Because JQuery === JavaScript and checking the `readystate` is not rocket science? Not to mention that the OP hasn't clarified whether the abort needs to happen on a successful response or all responses. – Scott Marcus Dec 29 '16 at 21:21
  • @ScottMarcus that's not a proper answer. If You use higher level library, so better keep convention of abstraction that it does. If tomorrow browsers will ignore `readystate` stuff, higher level library will have new build that will keep Your implementation code the same, just will do: `bower update` and that's all (: – num8er Dec 29 '16 at 21:22
  • @num8er Not true at all. JQuery is the most overused JavaScript library. So much so that there is a whole generation of developers that don't have the faintest idea of how JavaScript works because they just use JQuey. In many cases, performance is worse in JQuery and syntax is more complicated in JQuery. The use of JQuery should not be a given. – Scott Marcus Dec 29 '16 at 21:25
  • @ScottMarcus I am using these requests for a long-polling chat deployment. That is, the request keeps persisting on the serverside, not on the clientside. But when having more than one conversation, and clicking on them, several requests of ajax start. I wanted to cancel them whenever I changed the conversation. Have I been clearer? – AD Henrique Dec 29 '16 at 21:28
  • @ScottMarcus You cannot talk for others, jQuery is enough powerful and enough performant framework. All other problems are made by users of this framework. And for current quession it does not impact on performance. + I would inform You that bootstrap and many other libs depend on jQuery. So for current days nobody can ignore existence of it or totally avoid using it. – num8er Dec 29 '16 at 21:29
  • @ADHenrique That's a little better, but let me ask, why do you want to cancel only after the AJAX response has been received from the server? Why does that matter at all? If I click into a new conversation, don't you want to cancel the previous AJAX call(s) regardless of the state of the call? – Scott Marcus Dec 29 '16 at 21:30
  • @num8er Do what you like, but you are incorrect about performance implications and complexity of code in certain use cases. That's not an opinion. JQuery doesn't bring any new functionality to JavaScript (it IS JavvaScript). Using it relies on using wrappers that augment native functionality. Those wrappers come at a cost. That's programming 101. – Scott Marcus Dec 29 '16 at 21:32
  • @ScottMarcus I do not know if I was still clear. But it turns out that the server response is inserted into a div by "append". And when I click on another conversation, they are running 2 ajax at the same time. And the div is changing content, that is, in a request, append the messages of the first conversation and in the other request, append the messages of the second conversation ... Maybe because I'm using append? – AD Henrique Dec 29 '16 at 21:36
  • @ADHenrique Ok, I think this changes things. I would check the `readystate` to see if it isn't `4` (still running) and if so, cancel any pending AJAX call(s) **AND** I would then start a new call but simply reset the `div` where the old conversation was being shown. Let me update my answer again. – Scott Marcus Dec 29 '16 at 21:39
  • @ADHenrique One more question... If I've started one conversation and then I click into another line to start a second, should the first conversation be removed from my screen and then I only see the second or should I see the second conversation appended onto the first? – Scott Marcus Dec 29 '16 at 21:44
  • @ScottMarcus The first conversation will be removed from the screen. And it will show only the second or vice versa. No append ... – AD Henrique Dec 29 '16 at 21:47

2 Answers2

0

It turns out that the server response is inserted into a div by "append". And when I click on another conversation, they are running 2 ajax at the same time. And the div is changing content, that is, in a request, append the messages of the first conversation and in the other request, append the messages of the second conversation.

Just check the xhr.readystate value and if it isn't 4, abort the request and clear out the conversation related to that request.

Keeping track of active requests with your own Boolean flag can easily get out of sync with multiple requests if you are not setting the flag in all the right places. But the readystate property makes it so we don't have to manage any of that.

Also, you may need to cancel your interval timer when you cancel the AJAX request.

$('li.chat-conversation').on('click', function(){
  var xhr = null;
  var id = $(this).attr('data-conversation-id');

  var ajaxOpt = {...};

  var fn = function(){
    xhr = $.ajax(ajaxOpt);

    // Just check the readystate and if it's not 4 (DONE),
    // then cancel the current request.
    if(xhr.readystate !== 4){

        // Cancel the previous AJAX call(s)
        xhr.abort(); 

        // Clear out the conversation related to the request
        yourConversationDiv.textContent = "";

    } else if(xhr.readystate === 4 && xhr.status === 200){

        // Successful result, append to existing conversation
        yourConversationDiv.append(xhr.responseText);

    }
  };
});
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
0

Move xhr outside of click handler scope and check if it exists on click event:

var xhr = null;

$('li.chat-conversation').on('click', function() {
  var id = $(this).data('conversation-id');

  var ajaxOpt = {...};

  // when ajax request finished (does not matter success or failed)
  ajaxOpt.complete = function() { 
    xhr = null;
  };

  if(xhr) {
    xhr.abort(); 
  }
  xhr = $.ajax(ajaxOpt);
});



P.S. Extend my example Yourself (:

num8er
  • 18,604
  • 3
  • 43
  • 57