Cod*_*key 6 javascript dependency-injection circular-dependency angularjs
前段时间,我开始重构我的主项目代码,将业务逻辑从控制器解耦到服务,根据指南.一切顺利,直到我遇到循环依赖(CD)的问题.我读了一些关于这个问题的资源:
不幸的是,对我来说现在还不清楚,如何解决我项目的CD问题.因此,我准备了一个小型演示,它代表了我项目的核心功能:
组件简述:
问题1:gridMainService和gridDataService 之间存在循环依赖关系.第一个gridMainService使用gridDataService来加载具有以下功能的行数据:
self.loadRowData = function () {
// implementation here
}
Run Code Online (Sandbox Code Playgroud)
但是,gridDataService从服务器接收更新,并且必须在网格中插入一些行.所以,它必须使用gridMainService:
$interval(function () {
var rowToAdd = {
make: "VW " + index,
model: "Golf " + index,
price: 10000 * index
};
var newItems = [rowToAdd];
// here I need to get access to the gridMainService
var gridMainService = $injector.get('gridMainService');
gridMainService.gridOptions.api.addItems(newItems);
index++;
}, 500, 10);
Run Code Online (Sandbox Code Playgroud)
所以,我在这里遇到了第一张CD.
问题2:gridMainService和gridSettingsService 之间存在循环依赖关系.首先,gridMainService触发,当网格最初加载时,然后通过以下函数设置默认设置:
self.onGridReady = function () {
$log.info("Grid is ready, apply default settings");
gridSettingsService.applyDefaults();
};
Run Code Online (Sandbox Code Playgroud)
但是,要进行一些更改,gridSettingsService需要访问gridMainService及其对象gridOptions才能应用设置:
self.applyDefaults = function() {
var sort = [
{colId: 'make', sort: 'asc'}
];
var gridMainService = $injector.get('gridMainService');
gridMainService.gridOptions.api.setSortModel(sort);
};
Run Code Online (Sandbox Code Playgroud)
问题: 如何以正确的方式解决这些CD案例?因为,MiškoHevery博客很短,很好,但我没有设法将他的策略应用到我的案例中.
目前,我不喜欢手动注入的方法,因为我将不得不使用它很多,代码看起来有点模糊.
请注意: 我只准备了我的大项目的演示.您可以建议将所有代码放在gridDataService中并准备就绪.但是,我已经在这项服务中拥有500 LOC,如果我合并所有服务,那将是一场~1300 LOC的噩梦.
这类问题有很多解决方案,这取决于你的思维方式。我更喜欢认为每个服务(或类)都有一些目标,并且需要一些其他服务来完成其目标,但它的目标只有一个,明确且小。让\xe2\x80\x99s 通过这个视图查看你的代码。
\n\n问题一:
\n\nGridData:这里存放网格的数据。MainService 来这里是为了获取需要的数据,所以我们将其注入到 mainService 中,并像您一样使用 loadRowData 函数来获取 rowData 数据,但是在 $interval 中,您将 mainService 注入到 gridData 中,但 gridData 不需要\xe2\x80\x99 mainService 结束其目标(从服务器获取项目)。
\n\n我使用观察者设计模式(使用 $rootScope)解决了这个问题。这意味着当数据到达并且 mainService 来获取它们时我会收到通知。
\n\ngrid-data.service.js:
\n\nangular.module("gridApp").service("gridDataService",\n ["$injector", "$interval", "$timeout", "$rootScope",\n function ($injector, $interval, $timeout, $rootScope) {\n [\xe2\x80\xa6]\n $interval(function () {\n [..]\n self.newItems = [rowToAdd];\n\n // delete this code\n // var gridMainService = $injector.get(\'gridMainService\'); \n // gridMainService.gridOptions.api.addItems(newItems);\n\n // notify the mainService that new data has come!\n $rootScope.$broadcast(\'newGridItemAvailable\');\nRun Code Online (Sandbox Code Playgroud)\n\ngrid-main.service.js:
\n\n angular.module("gridApp").service("gridMainService",\n ["$log", "$q", "gridConfigService", "gridDataService", \'$rootScope\',\n function ($log, $q, gridConfigService, gridDataService, $rootScope) {\n [..]\n // new GridData data arrive go to GridData to get it!\n $rootScope.$on(\'newGridItemAvailable\', function(){\n self.gridOptions.api.addItems(gridDataService.getNewItems());\n })\n [..]\nRun Code Online (Sandbox Code Playgroud)\n\n当使用真实服务器时,最常见的解决方案是使用 Promise(而不是观察者模式),例如 loadRowData。
\n\n问题2:
\n\ngridSettingsService:此服务更改 mainService 的设置,因此它需要 mainService 但 mainService 不关心 gridSettings,当有人想要更改或了解 mainService 内部状态(数据,表单)时必须与 mainService 接口进行通信。
\n\n因此,我从 gridMainService 中删除了网格设置注入,只提供了一个接口,用于在网格就绪时放置回调函数。
\n\ngrid-main.service.js:
\n\nangular.module("gridApp").service("gridMainService",\n ["$log", "$q", "gridConfigService", "gridDataService", \'$rootScope\',\n function ($log, $q, gridConfigService, gridDataService, $rootScope) {\n [\xe2\x80\xa6]\n // You want a function to run onGridReady, put it here!\n self.loadGridOptions = function (onGridReady) {\n [..]\n self.gridOptions = {\n columnDefs: gridConfigService.columnDefs,\n rowData: gridDataService.rowData,\n enableSorting: true,\n onGridReady: onGridReady // put callback here\n };\n return self.gridOptions;\n });\n[..]// I delete the onGridReady function , no place for outsiders\n // If you want to change my state do it with the my interface\nRun Code Online (Sandbox Code Playgroud)\n\nAg-grid-controller.js:
\n\n gridMainService.loadGridOptions(gridSettingsService.applyDefaults).then(function () {\n vm.gridOptions = gridMainService.gridOptions;\n vm.showGrid = true;\n});\nRun Code Online (Sandbox Code Playgroud)\n\n这里是完整的代码:https://plnkr.co/edit/VRVANCXiyY8FjSfKzPna ?p=preview
\n