我正在寻找有关从本地JSON文件检索数据并处理响应的最佳方法的一些信息。在浏览Stack Overflow之后,我有一些不同的想法,因为我已经看到了多种做同样事情的方法(虽然没有解释为什么可能会优先考虑或不优选)。
基本上,我有一个Angular应用程序,它利用工厂从JSON文件中检索数据;然后我在我的html文件中使用它之前等待响应在我的控制器中解析,类似于下面的内容:
厂:
comparison.factory('Info', ['$http', function($http) {
var retrievalFile = 'retrievalFile.json';
return {
retrieveInfo: function() {
return $http.get(retrievalFile);
}
}
}]);
控制器:
comparison.controller('comparisonController', ['$scope', 'Info', function($scope, Info) {
Info.retrieveInfo().then(function(response) {
$scope.info = response.data;
});
}]);
我的主要观点是找出何时最好等待响应解决,或者甚至是否重要。我正在想让工厂恢复履行的承诺,并等待控制器也检索数据。在我看来,最好将所有数据检索抽象出控制器并进入工厂,但我不确定这是否延伸到等待工厂本身返回的实际数据。考虑到这一点,我对是否选择选项1或选项2感到困惑,并且非常感谢来自更有经验/合格开发人员的一些反馈!
厂:
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;
});
}]);
提前感谢您的任何意见/建议!
答案 0 :(得分:4)
这取决于您的控制器的期望以及您如何设置应用程序。一般来说,我总是选择第二种选择。因为我在所有api请求中通常都有全局错误或成功处理程序,并且我有共享api service
。像下面的东西。
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;
}]);
答案 1 :(得分:2)
这真的只是偏好。我喜欢用API来思考它。您想要公开的API是什么?您是否希望控制器接收整个响应,或者您希望控制器只获得响应所包含的数据?如果您只使用response.data
,则选项2效果很好,因为除了您感兴趣的数据之外,您永远不必处理任何事情。
一个很好的例子就是我在我工作的地方写的应用程序。我们有两个应用程序:后端API和我们的前端Angular应用程序。我们在前端应用程序中创建了一个API包装器服务。在服务本身中,我们为任何已记录错误代码的API端点放置.catch
(我们使用Swagger来记录和定义我们的API)。在.catch
中,我们处理这些错误代码并返回正确的错误。当我们的控制器/指令消耗服务时,它们会获得更严格的数据集。如果发生错误,那么UI通常是安全的,只显示从包装器服务发送的错误消息,并且不必担心查看错误代码。
同样,对于成功的回复,我们会在选项2中执行大部分操作。在许多情况下,我们会将数据细化为实际应用中最不实用的内容。通过这种方式,我们在服务中保留了大量的数据流和格式,而应用程序的其余部分则要做的事情要少得多。例如,如果我们需要基于该数据创建一个对象,我们只需将对象返回到promise链,这样控制器就不会在整个地方做到这一点。
答案 2 :(得分:1)
我会选择第二选项,因为它的选项实际上大致相同。但是,当我们添加像Person
假设的模型结构时,请看看。
comparison.factory('Info', ['$http', function($http) {
var retrievalFile = 'retrievalFile.json';
return {
retrieveInfo: function() {
return $http.get(retrievalFile).then(function(response) {
//we will return a Person...
var data = response.data;
return new Person(data.name, data.age, data.gender);
});
}
}
}]);
这非常简单,但是如果你必须将更复杂的数据映射到对象模型中(你可以检索具有自己项目的人员列表等等),那么当事情变得更复杂时,你可能想要添加处理数据和模型之间映射的服务。那么你有另一项服务DataMapper
(例子),如果你选择第一个选项,你必须将DataMapper
注入你的控制器,你必须通过你的工厂提出你的请求,并用注入的服务。然后你可能会说,我应该在这里拥有所有这些代码吗? ......很可能没有。
这是一个假设的案例,重要的是你如何构建代码,不会以你不理解的方式构建代码。最后看看这个:https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)并研究有关此原则的更多信息,但重点是javascript。
答案 3 :(得分:1)
好问题。几点:
模型(MVC中的M)是应用程序和的数据表示 将容纳数据逻辑。在Angular案例中,这将是一项服务 或正确指出的工厂类。为什么这样好 例如:
2.1 AccountsController(可能注入了多个数据模型)
2.1.1 UserModel
2.1.2 AuthModel
2.1.3 SubscriptionModel
2.1.4 SettingsModel
有很多方法可以采用数据模型方法,但我会说你的服务类应该是数据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);
})()