构建服务的正确方法是什么?

时间:2018-06-11 09:08:35

标签: angular angular-services circular-dependency

快乐的星期一开发者!

我向你提出了一个我无法自己回答的问题。

我目前正在构建一个应用程序,该应用程序从服务中获取大量数据,这些数据本身会产生一些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)
                })
    });
}

3 个答案:

答案 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)

你有两个问题:

  1. 如何在应用程序启动时从API加载数据。为此,您需要使用APP_INITIALIZER令牌。官方文档here和教程解释here

  2. 避免循环依赖。我认为您的主服务不能(也不应该)重复使用。 API调用本质上应该是异步的,但似乎您尝试按特定顺序运行它们。当你说"每当我从另一个服务导入这个主要服务时,你正在尝试做什么并不是很清楚。 - 采用你的示例代码,显然没有一个testservices 1..4可以导入main。因此,如果你有一个需要FIRST加载1..4的新服务器(testservice5),那么testservice5可以导入Main,然后那么做自己的工作。例如,即使testservice5与testservice1进行相同的API调用(当然这意味着你将有代码重复)。

  3. (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/