Javascript 角度-从工厂方法检索数据的最佳实践
我正在寻找一些关于从本地JSON文件检索数据和处理响应的最佳方法的信息。浏览堆栈溢出后,我有一些混合的想法,因为我看到了多种做同一件事的方法(尽管没有解释为什么一种可能更可取或不可取) 本质上,我有一个Angular应用程序,它利用工厂从JSON文件检索数据;然后,我等待响应在我的控制器中解析,然后在html文件中使用它,如下所示: 选择1 工厂:Javascript 角度-从工厂方法检索数据的最佳实践,javascript,angularjs,json,factory,Javascript,Angularjs,Json,Factory,我正在寻找一些关于从本地JSON文件检索数据和处理响应的最佳方法的信息。浏览堆栈溢出后,我有一些混合的想法,因为我看到了多种做同一件事的方法(尽管没有解释为什么一种可能更可取或不可取) 本质上,我有一个Angular应用程序,它利用工厂从JSON文件检索数据;然后,我等待响应在我的控制器中解析,然后在html文件中使用它,如下所示: 选择1 工厂: comparison.factory('Info', ['$http', function($http) { var retrievalFile =
comparison.factory('Info', ['$http', function($http) {
var retrievalFile = 'retrievalFile.json';
return {
retrieveInfo: function() {
return $http.get(retrievalFile);
}
}
}]);
comparison.factory('Info', ['$http', function($http) {
var retrievalFile = 'retrievalFile.json';
return {
retrieveInfo: function() {
return $http.get(retrievalFile).then(function(response) {
return response.data;
});
}
}
}]);
控制器:
comparison.controller('comparisonController', ['$scope', 'Info', function($scope, Info) {
Info.retrieveInfo().then(function(response) {
$scope.info = response.data;
});
}]);
comparison.controller('comparisonController', ['$scope', 'Info', function($scope, Info) {
Info.retrieveInfo().then(function(response) {
$scope.info = response;
});
}]);
我的主要争论点是弄清楚什么时候最好等回应解决,或者它是否重要。我只是想让工厂返回已兑现的承诺,然后等待控制器也检索数据。在我看来,最好是将所有数据检索从控制器中提取出来并放入工厂,但我不确定这是否扩展到等待在工厂内部返回实际数据。考虑到这一点,我对选择选项1还是选项2感到困惑,我非常感谢更有经验/资质的开发人员的反馈
选择2
工厂:
comparison.factory('Info', ['$http', function($http) {
var retrievalFile = 'retrievalFile.json';
return {
retrieveInfo: function() {
return $http.get(retrievalFile);
}
}
}]);
comparison.factory('Info', ['$http', function($http) {
var retrievalFile = 'retrievalFile.json';
return {
retrieveInfo: function() {
return $http.get(retrievalFile).then(function(response) {
return response.data;
});
}
}
}]);
控制器:
comparison.controller('comparisonController', ['$scope', 'Info', function($scope, Info) {
Info.retrieveInfo().then(function(response) {
$scope.info = response.data;
});
}]);
comparison.controller('comparisonController', ['$scope', 'Info', function($scope, Info) {
Info.retrieveInfo().then(function(response) {
$scope.info = response;
});
}]);
提前感谢您的任何意见/建议 我会选择选项二,因为你的选项基本上是一样的。但是让我们看看什么时候我们添加了一个模型结构,比如一个
Person
假设
comparison.factory('Info',['$http',function($http){
var retrievalFile='retrievalFile.json';
返回{
retrieveInfo:函数(){
返回$http.get(retrievalFile).then(函数(响应){
//我们将返回一个人。。。
var数据=响应数据;
返回新人员(data.name、data.age、data.gender);
});
}
}
}]);代码>这真的只是偏好。我喜欢从API的角度来考虑它。您要公开的API是什么?您是希望控制器接收整个响应,还是希望控制器只包含响应包装的数据?如果您只打算使用response.data
,那么选项2非常有用,因为除了您感兴趣的数据之外,您不需要处理任何事情
一个很好的例子是我们刚刚在我工作的地方编写的应用程序。我们有两个应用程序:后端API和前端Angular应用程序。我们在前端应用程序中创建了一个API包装器服务。在服务本身中,我们为任何记录了错误代码的API端点放置了一个.catch
(我们使用Swagger记录并定义了我们的API)。在该.catch
中,我们处理这些错误代码并返回正确的错误。当我们的控制器/指令使用该服务时,它们会返回一组更严格的数据。如果发生错误,UI通常可以安全地只显示从包装器服务发送的错误消息,而不必担心查看错误代码
同样,对于成功的回答,我们做了您在选项2中所做的大部分工作。在许多情况下,我们将数据细化到实际应用中最不有用的数据。通过这种方式,我们在服务中保留了大量的数据搅动和格式化,而应用程序的其余部分则没有那么多事情要做。例如,如果我们需要基于该数据创建一个对象,我们只需将该对象返回到承诺链,这样控制器就不会到处这样做。这取决于您的控制器期望什么以及您如何设置应用程序。一般来说,我总是选择第二种选择。这是因为我通常在所有api请求中都有全局错误或成功处理程序,并且我有一个共享的api服务
。像下面这样
var app = angular.module('app', []);
app.service('ApiService', ['$http', function($http) {
var get = function(url, params) {
$http.get(url, { params: params })
.then(handleSuccess, handleError);
};
// handle your global errors here
// implementation will vary based upon how you handle error
var handleError = function(response) {
return $q.reject(response);
};
// handle your success here
// you can return response.data or response based upon what you want
var handleSuccess = function(response) {
return response.data;
};
}]);
app.service('InfoService', ['ApiService', function(ApiService) {
var retrieveInfo = function() {
return ApiService.get(retrievalFile);
/**
// or return custom object that your controller is expecting
return ApiService.get.then(function(data) {
return new Person(data);
});
**//
};
// I prefer returning public functions this way
// as I can just scroll down to the bottom of service
// to see all public functions at one place rather than
// to scroll through the large file
return { retrieveInfo: retrieveInfo };
}]);
app.controller('InfoController', ['InfoService', function(InfoService) {
InfoService.retrieveInfo().then(function(info) {
$scope.info = info;
});
}])
或者,如果您使用的是路由器,您可以将数据解析到控制器中。ngRouter和uiRouter支持解决以下问题:
$stateProvider.state({
name: 'info',
url: '/info',
controller: 'InfoController',
template: 'some template',
resolve: {
// this injects a variable called info in your controller
// with a resolved promise that you return here
info: ['InfoService', function(InfoService) {
return InfoService.retrieveInfo();
}]
}
});
// and your controller will be like
// much cleaner right
app.controller('InfoController', ['info', function(info) {
$scope.info = info;
}]);
好问题。有两点:
控制器应该以视图为中心而不是以数据为中心,因此
希望从控制器中删除数据逻辑,而不是将其作为焦点
关于业务逻辑
模型(MVC中的M)是应用程序和应用程序的数据表示形式
将包含数据逻辑。在这种情况下,这将是一种服务
或者你正确指出的工厂类。为什么这对我来说很好
例如:
2.1 AccountsController(可能已注入多个数据模型)
有很多方法可以采用数据模型方法,但我想说,您的服务类应该是数据REST模型,即获取、存储、缓存、验证等。我已经提供了一个基本示例,但建议您研究JavaScript OOP,因为这将帮助您找到正确的方向,了解如何构建数据模型、集合,等等
下面是一个用于管理数据的服务类示例。请注意,我还没有测试过这段代码,但它应该会给您一个开始
例如:
(function () {
'use strict';
ArticleController.$inject = ['$scope', 'Article'];
function ArticleController($scope, Article) {
var vm = this,
getArticles = function () {
return Article.getArticles()
.then(function (result) {
if (result) {
return vm.articles = result;
}
});
};
vm.getArticles = getArticles;
vm.articles = {};
// OR replace vm.articles with $scope if you prefer e.g.
$scope.articles = {};
$scope.userNgClickToInit = function () {
vm.getArticles();
};
// OR an init on document ready
// BUT to honest I would put all init logic in service class so all in calling is init in ctrl and model does the rest
function initArticles() {
vm.getArticles();
// OR chain
vm.getArticles()
.then(getCategories); // doesn't here, just an example
}
initArticles();
}
ArticleModel.$inject = ['$scope', '$http', '$q'];
function ArticleModel($scope, $http, $q) {
var model = this,
URLS = {
FETCH: 'data/articles.json'
},
articles;
function extract(result) {
return result.data;
}
function cacheArticles(result) {
articles = extract(result);
return articles;
}
function findArticle(id) {
return _.find(articles, function (article) {
return article.id === parseInt(id, 10);
})
}
model.getArticles = function () {
return (articles) ? $q.when(articles) : $http.get(URLS.FETCH).then(cacheArticles);
};
model.getArticleById = function (id) {
var deferred = $q.defer();
if (articles) {
deferred.resolve(findArticle(id))
} else {
model.getBookmarks().then(function () {
deferred.resolve(findArticle(id))
})
}
return deferred.promise;
};
model.createArticle = function (article) {
article.id = articles.length;
articles.push(article);
};
model.updateArticle = function (bookmark) {
var index = _.findIndex(articles, function (a) {
return a.id == article.id
});
articles[index] = article;
};
model.deleteArticle = function (article) {
_.remove(articles, function (a) {
return a.id == article.id;
});
};
}
angular.module('app.article.model', [])
.controller('ArticleController', ArticleController)
.service('Article', ArticleModel);
})()
并非总是最好的答案,但Angular的美妙之处在于它不关心如何为您的“模型”处理或维护数据。我看到的最佳实践与选项1类似。我认为从可读性的角度来看,它在服务、数据和控制器之间提供了一个很好的链接。不过这只是我的意见:-DI建议选择1,因为您将在其中的所有方法上使用命令,如successCallback和errorCallback。使用promise(即angular$q服务)会更好。谢谢你(以及其他回答的人),这绝对是值得思考的。我将研究编写一个API服务,以便我的代码易于扩展。