快乐的星期一开发者!
我向你提出了一个我无法自己回答的问题。
我目前正在构建一个应用程序,该应用程序从服务中获取大量数据,这些数据本身会产生一些API请求。
现在我需要在我的应用程序可供用户使用之前完成所有这些API调用。
现在我的问题是:"构建依赖数据的应用程序结构的正确方法是什么?
目前已实施的解决方案:
每个服务本身都有一些函数,然后创建一些HTTP get请求。
我目前有一项主要服务,可以导入所有其他服务。 然后,我接着一个接一个地控制着流量。 现在,如果我想在应用程序开始时执行此操作,这可以很好地工作。 但我现在也希望在运行我的应用程序时执行这些相同的调用。 但是每当我从另一个服务导入这个主服务时,我就会创建一个循环依赖,因为主服务会导入所有可用的服务。
现在,处理此问题的正确方法是什么? 我需要有一个我可以调用的函数,它可以检索我的应用程序所需的所有数据,并且我应该能够从我的应用程序中的任何组件和/或服务中调用此函数,而不会创建循环依赖。
你们怎么解决这个问题?是否有最好的做法?
**仅供参考,这不是一个标准的应用程序,而是一个' kiosk'。我们最初想要获取所有数据,以便几乎不必加载应用程序。此外,当我调用该函数重新检索所有数据时。 **
主要服务代码示例:
constructor(
private testservice1: TestService1,
private testservice2: TestService2,
private testservice3: TestService3,
private testservice3: TestService4
) {
this.loading = true;
this.getApplicationLogic()
.then(() => {
this.loading = false;
})
}
public getApplicationLogic() {
return new Promise((resolve, reject) => {
testservice1.getTest()
.then(
res => {
testservice1.setTestConfig(res);
return this.testservice2.getTest2();
},
msg => {
throw new Error(msg)
})
.then(
res => {
testservice2.setTestConfig(res);
return this.testservice3.getTest3();
},
msg => {
throw new Error(msg)
})
.then(
res => {
testservice3.setTestConfig(res);
resolve();
},
msg => {
throw new Error(msg)
})
});
}
答案 0 :(得分:0)
您可以通过注入func getUserDetail() -> UserDetail? {
if let decodedData = UserDefaults.standard.object(forKey: AppConstant.userDefaultKey.user_detail) as? Data {
return try! PropertyListDecoder().decode(UserDetail.self, from: decodedData)
}
return nil
}
func setUserDetail(user: UserDetail) {
UserDefaults.standard.set(try! PropertyListEncoder().encode(user), forKey: AppConstant.userDefaultKey.user_detail)
}
而不是导致循环依赖的服务之一来解决循环依赖关系
Injector
我不知道代码的复杂性。但是如果你跨越任何循环依赖,那么你可以应用它。
答案 1 :(得分:0)
你有两个问题:
如何在应用程序启动时从API加载数据。为此,您需要使用APP_INITIALIZER令牌。官方文档here和教程解释here。
避免循环依赖。我认为您的主服务不能(也不应该)重复使用。 API调用本质上应该是异步的,但似乎您尝试按特定顺序运行它们。当你说"每当我从另一个服务导入这个主要服务时,你正在尝试做什么并不是很清楚。 - 采用你的示例代码,显然没有一个testservices 1..4可以导入main。因此,如果你有一个需要FIRST加载1..4的新服务器(testservice5),那么testservice5可以导入Main,然后那么做自己的工作。例如,即使testservice5与testservice1进行相同的API调用(当然这意味着你将有代码重复)。
(2)的更好的解决方案是不设计服务以特定的预定义顺序执行,但允许每个服务彼此独立地激发,存储数据并具有某种全局跟踪器每个服务完成后更新(返回数据)。
例如,在应用启动时,您说要完成4项服务。触发第一个,在其结果中,您将标志更新为1并触发事件。您的第二个服务侦听该事件并运行。在其结果中,您将标志更新为2,然后再次触发该事件。服务3侦听该事件并运行,更新标志等。
通过这种方式,您可以在启动时按照定义的顺序使用所有4项服务,但仍然可以将每项服务作为单独的自包含的事物进行处理。您在应用程序运行时稍后重复使用。
答案 2 :(得分:0)
通常我使用一般appstate服务构建服务,该服务保存全局设置(如后端服务器URL),这是一个处理通用http请求的http服务,例如
export class MyHttpService{
constructor(
private http: HttpClient,
private app: AppstateService,
private log: LogService
) { }
getRest<T>(api: string) {
let opts = this.getOptions();
return this.http.get<T>(this.app.backurl + "/api/v1/" + api, opts);
}
和实现高级api的api服务,例如
export class MyapiService {
constructor(private myhttp: MyHttpService) {}
GetOperations(pt_id: number) {
this.myhttp.getRest<DashboardOperations>( "GetDashboardOperations?pt_id="
+ pt_id ).pipe(map(resp=> resp.data));
}
最终组件只处理api服务以获取订阅数据。
如果您不希望应用在每次刷新信息时获取所有数据,您可以考虑使用pouchdb存储数据,并将其与服务器同步(请参阅https://www.sitepoint.com/offline-web-apps-service-workers-pouchdb/)