Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it possible to abort requests #3

Open
deepxg opened this issue Oct 9, 2016 · 6 comments
Open

Make it possible to abort requests #3

deepxg opened this issue Oct 9, 2016 · 6 comments
Milestone

Comments

@deepxg
Copy link

deepxg commented Oct 9, 2016

It's common to want to abort an in-progress HTTP request, perhaps if a more recent request comes along (for example the case of multiple autocomplete requests), or if the user navigates away and it is no longer relevant.

How might I go about holding on to handlers (perhaps in :db) so that I can later handle them? Or would it be better to have an API that allowed a programmer to specify some sort of identifier for each request, such that multiple requests with the same identifier caused the previous one to abort?

@danielcompton
Copy link
Contributor

This is an interesting question. There is the capability in cljs-ajax and goog.XhrIO to abort requests, the question is how to do this with re-frame. One possibility is that users specify an additional :id key, and we create a new fx called :abort-http-xhrio which takes ids to cancel.

Or would it be better to have an API that allowed a programmer to specify some sort of identifier for each request, such that multiple requests with the same identifier caused the previous one to abort?

This is an interesting idea which could simplify some kinds of code, like debouncing search results.

@deepxg
Copy link
Author

deepxg commented Oct 11, 2016

Yeah, purely for debouncing I often have code like this:

(reg-event-fx
 :app/store-debounced-event
 (fn [{db :db} [_ event timestamp]]
   {:db (assoc-in db [:app/debounce (first event)] {:timestamp timestamp :event event})}))

(reg-event-fx
 :app/dispatch-debounced-event
 (fn [{db :db} [_ event timestamp]]
   (let [{latest-timestamp :timestamp event :event} (get-in db [:app/debounce (first event)])]
     (if (= timestamp latest-timestamp)
       {:db (update db :app/debounce dissoc (first event))
        :dispatch event}))))

(reg-event-fx
 :app/debounce-event
 (fn [{db :db} [_ event]]
   (let [timestamp (.getTime (js/Date.))]
     {:dispatch [:app/store-debounced-event event timestamp]
      :dispatch-later [{:ms 500 :dispatch [:app/dispatch-debounced-event event timestamp]}]})))

Which is easy to wrap in an effect handler. But I suspect there's a more general case, as I'll often want to kill off slow requests when navigating. There's even perhaps a wider (re-frame) point that currently effect handlers aren't that extensible, because they expose no data themselves - in this case it would be good to get a map out of all the current requests, so you could handle aborting requests without having to inspect or copy the actual implementation of http-fx.

@flexsurfer
Copy link

i need this functionality too, and for me would be better to have something like :on-request [:my-event], where request object will be passed, easiest and flexible way i think

@flexsurfer
Copy link

@danielcompton what do you think? can i make a PR?

@kennethkalmer
Copy link
Contributor

I just came here looking for the same reason. I have some very long running queries, and currently I manually build the requests for those using the re-frame-http-fx plumbing (just so it looks the same). I'm refactoring and wanted things to be consistent and hit the two spots where I use (ajax/abort req) and just realized I'm falling short.

My gut says @flexsurfer's :on-request is a starting point that is definitely good enough.

The dispatcher can then decide what to do with the raw request, save it in the app-db and then manipulate it later. One caveat is that some cleanup needs to happen in both :on-success and :on-failure, but that is up to the caller and should be documented clearly.

@nenadalm
Copy link

nenadalm commented Feb 7, 2019

Hi. I was thinking about it and maybe two additional keys could be added to the event?

:id - id under which request would register possibly inside some local atom when started and unregister when completed. If second request with the same id would come along before first one would finish, first one would be aborted.
:when - predicate taking db and returning bool (e.g. (fn [db] (= (:page db) :user-list)). This predicate would say if request is still valid (user is still on the page, search query didn't change...) and if it returns failse, events shouldn't be triggered even if response arrived.

Ideally when event is in progress and :when condition changes, request should be immediately aborted. Only way to do this now is probably by attaching watch on the app-db atom?

I could send pr if this is acceptable.

@superstructor superstructor self-assigned this May 14, 2019
@superstructor superstructor added this to the 0.2.0 milestone May 15, 2019
@superstructor superstructor modified the milestones: 0.2.0, 0.3.0 Nov 6, 2020
@superstructor superstructor removed their assignment Nov 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants