javascript - 如何防止在一条路由中启动的慢速 $http 在用户更改路由后可能解析?

标签 javascript angularjs angularjs-routing

假设我当前的路由是/books,我调用 $http 来获取我们想要向用户展示的所有书籍。通常,调用会很快解决,书籍会被 ng-repeated 到 DOM 中。但是,当我们遇到错误时(例如超时或没有归还书籍),我们会更新一个通用的全局 View ,该 View 将覆盖内容 View 并显示一条消息,例如“没有可用的书籍”。公共(public) View 通过服务处理,方法包括 CommonView.showLoading()、CommonView.showError("There are no books available.") 和 CommonView.hide() 等。

最近,我发现如果不快速解析$http,用户可能会离开并转到另一条路线(可能是/dinosaurs)。最终,当 $http 最终解析或被拒绝时,会调用 promise 来显示通用的全局 View ,导致在不应该显示错误 View 的情况下显示错误 View ,并且该错误对用户(即,用户位于/dinosaurs,错误屏幕弹出“没有可用的书籍。”)。

我已经看到您可以取消带有超时 promise 的 $http,但这似乎仍然会导致竞争条件(也许您在 resolve() 或 reject() 处理开始后调用 cancel)。我认为必须检查当前路由是否与启动 $http 的路由相匹配会很麻烦。

似乎应该有一些标准的方法来销毁路由更改或 Controller 的 $destroy 方法中的 $http 调用。我真的很想避免在我庞大的应用程序中添加大量条件。

最佳答案

如果我的回调已经开始,我找不到停止处理的好方法,但这是我制作的 $http 包装器,用于尝试阻止延迟回调在路由更改后被调用。它不会复制所有 $http 方法,只复制我需要的那些。我也没有完全测试过它。我只验证过它可以在正常条件下工作(标准调用的正常带宽,即 httpWrapper.get(url).success(cb).error(err))。您的里程可能会有所不同。

angular.module('httpWrapper', []).provider('httpWrapper', function() {
    this.$get = ['$rootScope','$http','$q', function($rootScope, $http, $q) {
        var $httpWrapper = function(config) {
        var deferred = $q.defer();
        var hasChangedRoute = false;
        var canceler = $q.defer();
        var http = null;
        var evListener = null;
        var promise = deferred.promise;

        if ((config || {}).timeout && typeof config.timeout === 'Object') {
            // timeout promise already exists
            canceler.promise = config.timeout;
        } else {
            angular.extend(config || {}, {
                timeout: canceler.promise
            });
        }
        http = $http(config)
            .success(function(data, status, headers, config) {
                // only call back if we haven't changed routes
                if (!hasChangedRoute) {
                    deferred.resolve({data:data, status:status, headers:headers, config:config});
                }
            })
            .error(function(data, status, headers, config) {
                // only call back if we haven't changed routes
                if (!hasChangedRoute) {
                    deferred.reject({data:data, status:status, headers:headers, config:config});
                }
            });

            evListener = $rootScope.$on('$locationChangeStart', function(scope, next, current) {
                hasChangedRoute = true;
                canceler.resolve('killing http');
                evListener(); // should unregister listener
            })

            promise.success = function(fn) {
                promise.then(function(response) {
                    fn(response.data, response.status, response.headers, config);
                });
                return promise;
            };
            promise.error = function(fn) {
                promise.then(null, function(response) {
                    fn(response.data, response.status, response.headers, config);
                });
                return promise;
            }
            return promise;
        };

        angular.forEach(['get', 'delete', 'head', 'jsonp'], function(method) {
            $httpWrapper[method] = function(url, config) {
                return $httpWrapper(
                    angular.extend(config || {}, {
                        method: method,
                        url: url
                    })
                );
            };
        });
        angular.forEach(['post', 'put'], function(method) {
            $httpWrapper[method] = function(url, data, config) {
                return $httpWrapper(
                    angular.extend(config || {}, {
                        method: method,
                        url: url,
                        data: data
                    })
                );
            };
        });
        return $httpWrapper;
    }];
});

关于javascript - 如何防止在一条路由中启动的慢速 $http 在用户更改路由后可能解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24062940/

相关文章:

javascript - 创建自定义指令不起作用

javascript - 无法发送包含特殊字符的密码(用空格代替)

javascript - 是否可以定义一个解析对象并使其在所有路由中可用?

javascript - AngularJS 指令对属性更改没有反应

javascript - react js 获取 API

javascript - 基础 6 + webpack : Cannot make Foundation JS work

javascript - iOS Chrome 和 AngularJS 不执行 HEAD 中的 Controller

javascript - 路由提供未找到AngularJs

javascript - nvd3 带对数刻度的气泡图

javascript - 当css值改变时触发事件