假设我当前的路由是/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/