如何在javascript中取消异步进程?

如何在javascript中取消异步进程?,javascript,jquery,asynchronous,Javascript,Jquery,Asynchronous,我有一个单窗口javascript应用程序。我有一个仪表板,通过在后台通过多个get请求加载来显示某些图像 当不是所有get请求都按时完成并且站点的上下文发生变化时,就会出现问题,因为我想清除仪表板。但是,如果get请求尚未完成,它们将用错误的图像填充仪表板 我正在想办法中止那些get请求。有人能告诉我正确的方向吗 var Dashboard = { showAllAssets: function(){ var self = this; this.rese

我有一个单窗口javascript应用程序。我有一个仪表板,通过在后台通过多个get请求加载来显示某些图像

当不是所有get请求都按时完成并且站点的上下文发生变化时,就会出现问题,因为我想清除仪表板。但是,如果get请求尚未完成,它们将用错误的图像填充仪表板

我正在想办法中止那些get请求。有人能告诉我正确的方向吗

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();
    }
}

正如注释所指出的,一种可能的解决方案是存储当前上下文,并在get请求的success方法中对其进行比较

到目前为止,我已经更改了代码,现在我将在管理器中存储当前事件,并将事件传递给
$.get
-方法

这有一个缺点,即get请求仍在处理中,如果要处理的get请求太多,则加载新上下文需要更长的时间,因为这些get请求将在稍后处理。我也不喜欢把这件事传给别人

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);
        })
    }
}

我创建了一个不同的解决方案,将请求存储在一个数组中,并在上下文更改时中止它们:

    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;
            }
        });
    },

虽然您无法停止已发送的请求,但仍然可以解决您的问题

我的解决方案是生成一个简单的ID,例如一组随机数字,并将其存储在仪表板中的某个位置,然后将其与请求一起发送,并将其与图像一起发送回

如果生成一个新的上下文,它将有一个新的ID


如果图像返回时的ID与当前上下文中的ID不同,则将其丢弃。

可能不尝试取消请求,但在完成后,请在加载图像之前检查上下文是否相同。@ElliotBonneville这是一种有效的解决方法。如何存储当前上下文?我不太确定应该如何设置并比较get请求的success方法中的状态。我不太理解代码某些部分背后的原因(获取更多资产的setTimeout?),但如果您将所有这些请求包装在$.when()中,并一次性处理它们,再添加一个promise对象是很容易的,您可以拒绝该对象,从而有效地中止正在处理的任何一个对象,而不实际中止请求(避免控制台中显示错误),但一次触发的请求过多应该不是问题(除非您一次处理数百个请求,否则我想……在这种情况下,您应该重新考虑如何减少请求数量)。setTimeout使停止这些请求变得特别困难,因为您不仅必须中止现有请求,而且还必须逐个清除所有尚未完成的超时。当解决方案看起来有点过于复杂时,只测试上下文可能更容易(我没有任何建议,因为我不确定您的案例中的具体情况。)