3

I have a one-window javascript application. I have a dashboard that displays certain images by loading via multiple get requests in the background.

Problem arises when not all get requests are finished on time and the context of the site changes because then I want to clear the dashboard. Yet if the get request havent't finished yet, they will populate the dashboard with the wrong images.

I am trying to think of a way to abort those get request. Can someone please direct me in the right direction?

var Dashboard = {
    showAllAssets: function(){
        var self = this;
        this.resetDashboard();

        $.get(this.urlForAllAssets, function(json){
           self.loadAssets(json);
        });

    },
    showAssetsForCategory: function(categoryId) {
        ...

    },
    getHtmlForAsset: function(id) {
        var self = this;
        $.get(this.urlForDashboardThumb + "/" + id.toString(), function(assetHtml){
            var $asset = $(assetHtml);
            self.insertAssetThumbIntoDom($asset);
            // this gets inserted even when context changed, how can I prevent that?
            var thumb = Object.create(Thumbnail);
            thumb.init($asset);
        }, 'html')
    },
    insertAssetThumbIntoDom: function($asset) {
        $asset.appendTo(this.$el);
    },
    resetDashboard: function() {
        this.$el.html("");
    },
    loadAssets: function(idList) {
        var self = this;
        var time = 200;

        // These get requests will pile up in the background

        $.each(idList, function(){
            var asset = this;
            setTimeout(function(){
                self.getHtmlForAsset(asset.id);
            }, time);
            time += 200;
        });
    },
    bind: function() {
        $document.on('loadAssets', function(event, idList) {
            self.loadAssets(idList);
        });

        $document.on('switched_to_category', function(event, categoryId) {
            self.showAssetsForCategory(categoryId);
        });

        $document.on('show_all_assets', function(){
            self.showAllAssets();
        })
    },
    init: function($el) {
        this.$el = $el;
        this.resetDashboard();
        this.bind();
    }
}
7
  • 4
    Maybe don't try to cancel the request, but after it's finished check to see if the context is the same before loading the images. Commented Jan 30, 2014 at 18:13
  • @ElliotBonneville That would be a valid workaround. How would you store the current context? I am not quite sure how I should set and then compare the state within the success method of the get request. Commented Jan 30, 2014 at 18:23
  • I don't quite understand the reasoning behind certain parts of your code (the setTimeout around getting more assets?) but if you wrapped all of these requests in a $.when() and handled them all at once, it would be easy to add one more promise object that you can reject to effectively abort any of them being processed without actually aborting the requests (avoiding errors showing in the console) Commented Jan 30, 2014 at 18:24
  • 1
    too many requests being fired at once though shouldn't be a problem (unless you're dealing with hundreds at a time i guess... in that case you should re-think the way this works towards reducing the number of requests requried). The setTimeout makes it particularly difficult to stop these requests because not only do you have to abort existing requests, but you also have to clear all of the timeouts that haven't already completed, one by one. Commented Jan 30, 2014 at 18:30
  • 1
    the $.when solution seems a bit too overcomplicated, it would likely be easier to just test the context (which i don't have a suggestion for, as i'm not sure exactly what a context is in your case.) Commented Jan 30, 2014 at 18:53

3 Answers 3

1

Though you cant stop an already sent request, you can still solve your problem.

My solution is to generate a simple ID, a random set of numbers for example, and store somewhere in your dashboard, and send it along with the request and send it back with the image.

If a new context is generated, it will have a new ID.

If the image comes back with a different ID than the one in the current context, then discard it.

Sign up to request clarification or add additional context in comments.

Comments

0

As pointed out by the comments, a possible solution is to store the current context and compare it within the success method on the get request.

I have changed my code insofar that now I'll store the current within the manager and also I pass the event around to the $.get-method.

This has the downside that the get requests are still processed though and the loading of the new context takes longer as those get requests are processed later if there are too many to process. I also dislike passing the event around.

var Dashboard = {
    currentLoadEvent: null,
    loadAssets: function(idList, event) {
        var self = this;

        $.each(idList, function(){
            var asset = this;
            self.getHtmlForAsset(asset.id, event);
        });
    },
    getHtmlForAsset: function(id, event) {
        var self = this;
        $.get(this.urlForDashboardThumb + "/" + id.toString(), function(assetHtml){
            if (event === self.currentLoadEvent) {
                console.log('same event continuing');
                var $asset = $(assetHtml);
                self.insertAssetThumbIntoDom($asset);
                var thumb = Object.create(Thumbnail);
                thumb.init($asset);
            } else {
                console.log('context changed');
            }
        }, 'html')
    },
    bind: function() {
        var self = this;

        $document.on('loadAssets', function(event, idList) {
            self.currentLoadEvent = event;
            self.loadAssets(idList, event);
        });

        $document.on('switched_to_category', function(event, categoryId) {
            self.currentLoadEvent = event;
            self.showAssetsForCategory(categoryId, event);
        });

        $document.on('show_all_assets', function(event){
            self.currentLoadEvent = event;
            self.showAllAssets(event);
        })
    }
}

Comments

0

I created a different solution by storing the request in an array and aborting them when the context changed:

    loadAssets: function(idList, event) {
        var self = this;
        var requests = [];

        $.each(idList, function(){
            var asset = this;
            if (self.currentLoadEvent === event){
                var request = $.get(self.urlForDashboardThumb + "/" + asset.id.toString(), function(assetHtml){
                    if (event === self.currentLoadEvent) {
                        var $asset = $(assetHtml);
                        self.insertAssetThumbIntoDom($asset);
                        var thumb = Object.create(Thumbnail);
                        thumb.init($asset);
                        console.log('completed get request');
                    } else {
                        console.log('context changed');
                        $.each(requests, function(){
                            this.abort();
                            console.log('aborted request');
                        })
                    }
                }, 'html');
                requests.push(request);
            } else {
                return false;
            }
        });
    },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.