0

I'm using cujojs/rest to send requests to my (laravel) API. I'm looking for a way to cancel requests that are not over when a new one comes in.

There is a cancel method on the client which may be what I need to solve my problem :

My app displays a paginated collection of items, people can browse pages by clicking a "next/prev" button. If the user clicks multiple times on the 'next' button quickly every new page will fire of a new request. I'd like to make sure that only the latest request gets going and all the other (unfinished) ones are aborted.

I used to do this with a beforeSend method when I was using another tool to perform my requests. It would add the xhr object to an array and before a request was fired it would call .abort() on all the xhr in that array if they were not over.

Now that I switched to cujojs/rest, I can't figure out how the cancel method could be used to accomplish that.

Of course I don't want to abort any request before a new one is run, just the ones that tap the same resource as I might have unrelated data loading elsewhere.

/users?page=1 -> should be canceled
/users?page=2 -> should be canceled
/preferences  -> should NOT be canceled
/users?page=3 -> should be canceled
/users?page=4 -> should go through as its the last one

Any help would be very appreciated.

Romain
  • 313
  • 3
  • 5
  • once request is sent you can not cancel it because cancel will be another request which won't be delivered to the server-side faster than the previous one so you need to filter it in your code when you get the response – guramidev Oct 02 '15 at 05:54
  • but isn't it what you do when using beforeSend : http://stackoverflow.com/questions/4551175/how-to-cancel-abort-jquery-ajax-request – Romain Oct 02 '15 at 11:35
  • beforeSend event fires exactly as it's writte, meaning BEFORE the request is sent. once it is sent technically you can never cancel it sadly. But its logical though. But as i understand you need to cancel it before it is sent and the question is how to do it with cujojs – guramidev Oct 02 '15 at 15:23
  • if you provide your code i may be able to help. it seems that cujojs has cancel method, so basically before sending request you could run .cancel() and it would cancel all requests that are not sent yet – guramidev Oct 02 '15 at 15:39
  • Right, I'm building an app with VueJs. I'm watching a "page" property, when it changes it fires a fetch method again. – Romain Oct 03 '15 at 08:12

1 Answers1

2

I am not sure because there is no proper documentation as far as i can find. But judging from the source code you should be able to do something like this

//lets say you defined **this.request** somewhere in the constructor to hold the request value which defaults to empty object {};

fetchCollection: function(id) {

var that = this;
var url = 'collections/' + id;

if( Object.keys( that.request ).length !== 0 ) {

    if( 'function' === typeof that.request.cancel )
         that.request.cancel();
    else
         that.request.canceled = true;

  //here we should re-assign the default {} value again
  that.request = {};


}
that.request.path = url;

return client( that.request ).then(
        function(response){
            that.collection = response.entity.data;
        },
        function(response){
            console.error(response.status.code, response.status);
        }
    );
},

If it works i can explain why.

Ok so now when it works i can explain why using pseudo-code:

Inside client( request ) function cujojs before doing anything does this:

  1. Checks if request.canceled exists and is equal to true

  2. Aborts request if condition is met

If request.canceled doesn't exist it continues and goes to next step

  1. cujojs defines request.cancel function which can abort the request before it is sent ( we don't care about steps after because cancelation is our intention )

Now what we are doing is we are using javascripts innate ability to pass variables by reference. By reference means that when you are giving create() function a variable request the function uses this same variable inside of itself, instead of creating a brand new copy of the variable request and using that copy.

The way we are exploiting this here is that we are manipulating request variable from outside of cujojs knowing that it is using the same variable thus our manipulation will directly affect request variable cujojs is using at the time of execution create() function.

Now that we know that cujojs has 2 methods of canceling request, and that we can manipulate request variable after create() function received it we do a simple checking on our side:

  1. We check if this.request is empty ( it will only be empty if no request was sent yet )

  2. If it is not empty we check whether cujojs already has defined the .cancel function on our request variable by doing 'function' === typeof request.cancel

  3. if it had we can use this function to cancel the request we sent previously, if it hadn't we know that cujojs is for now on the step which checks .canceled variable on our request variable so we assign this to true doing this.request.canceled = true;

  4. After canceling the request, we assign request brand new value {} thus losing the reference to our previous request variable which we manipulated earlier

I am very poor at explaining things but i hope you understood, knowing such nuances will help you a lot in your development.

Happy coding

guramidev
  • 2,228
  • 1
  • 15
  • 19
  • wouldn't mind a bit of explanation if you have time. I'll need to find a way to extract this as I do this a lot. Thank you so much ! – Romain Oct 03 '15 at 13:53
  • Maybe this could be handled in an interceptor.. they have a timeout interceptor (https://github.com/cujojs/rest/blob/master/interceptor/timeout.js). the functionality is a bit similar. But it should only cancel the identical requests (except for page query for instance). This is too much over my head though. – Romain Oct 03 '15 at 13:59
  • i added the explanation. If you think you can continue from here on its cool, otherwise just write and i will try to wrap it in a reusable piece of code. It would just be hard because i don't know anything about cujojs and node.js so will not be able to test it out before responding.What i want to say is it would be better if you understood how it is working and applied it to your cujojs knowledge. But then again if something just write here. – guramidev Oct 03 '15 at 15:00