如何在不使用承诺的情况下通过 HTTP 检索数据

How to retrieve data via HTTP without using promises

我有以下服务代码我简化了发布在这里

    Load(Channel: any) {
        // 
        let URL = Globals.AppSiteRoot + Channel.URL
        return this.LoadData(URL)
    }

    Load_Default() {
        let URL = Globals.AppSiteRoot + "dir1/somedata.XML"
        console.log("XYZService.Load_Default------.------>>URL", URL)
        //
        return this.LoadData(URL)
            .then(data => {
                {
                    // do some processing here
                    console.log("XYZService.Load_Default<<P------.------data", data)
                    console.log("XYZService.Load_Default<<P------.------This.Data", this.Data)
                }
            });
    }

    // https://medium.com/@balramchavan/using-async-await-feature-in-angular-587dd56fdc77
    // https://v5.angular.io/api
    // https://v5.angular.io/guide/comparing-observables
    LoadData(URL: string) {  // : Observable<any>

        return new Promise(resolve => {
            // first argument is URL, put config as second argument
            // return this.http.get(URL, {responseType: 'text'})
            this.HttpClient.get(URL)
                .map(res => res)
                .subscribe(
                    data => {
                        // 
                        console.log("XYZService.LoadData<<P------.------http.get=>data", data)
                        // Do some processing here, if needed...
                        this.Data = data
                        // return new Observable(this.Data);  
                        resolve(this.Data)
                    }
                    ,
                    err => {
                        // https://forum.ionicframework.com/t/handle-errors-with-http-services/53229
                        console.log("XYZService.LoadData<<P------.------http:ERR", err)
                    }
                );
        });
    }

在 XYZ 组件中,我执行以下操作:

Show(Channel: any) {
        console.log("XYZComponent.Show------.------>>Channel>>" + Channel.URL)
        //
        this.XYZService.Load(Channel)
            .then(data => {
                console.log("XYZComponent.Show------.------>>data", data)  
                this.NavController.parent.select(1);
            });            
    }

如果我切换到使用 async/await,我的组件代码会变成这样,我必须承认,一旦接受 await 是阻塞的,代码看起来比使用 Promise .then....

    async ShowV2(Channel: any) {
        console.log("XYZComponent.Show------.------>>Channel>>" + Channel.URL)
        //
        const data = await this.XYZService.Load(Channel)
        console.log("XYZComponent------.------>>data", data)
        // 
        this.NavController.parent.select(1)
    }

我从我阅读的许多帖子和博客中得到了混合信息。

有人说,如果您希望只接收一次数据,请不要使用 HttpClient.get.subscribe...,而是使用 .toPromise(),但是他们从不展示如何处理错误。

有人说 async/await 只是糖语法,仍在底层使用 Promises。

有人说 Observables 更好,甚至 Angular 广泛使用它们。

关于 .Load() .Load_Default() 和组件 .Show() 方法中的代码,这些是期望 Observables 的地方以及如何对其进行编码?

我在别处使用 ReplaySubject(1) 来广播来自服务的事件并在页面之间进行间接通信。但是,我不确定这是另一个使用它的地方。

我对像 ReplaySubject(1) 这样的事件发射器的典型关注,尤其是当我在几个月后访问代码时,

1) 我如何确保只订阅一次活动?在哪里?

2) 我退订了吗?在哪里退订?

顺便说一句,即使我使用的是 Promises、Observables、ReplaySubject(1),这对我来说都是中文,并且是实现我显示一些数据或我从中检索的一些图片的简单目标时分心和沮丧的重要来源网络。 因此,如果你有一个 approach/pattern 来清楚地写下代码,这样当我四个月后回来时,一切都有意义:)

请包含您将在生产中使用的错误处理模板代码。 感谢您分享您的任何见解。

npm show ionic version
5.4.16
npm show cordova version
9.0.0
npm show angular version
1.7.9
show @angular/core version
9.0.6
ng --version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 9.0.4
Node: 10.16.0
OS: win32 x64

Angular: 5.0.3
... common, compiler, compiler-cli, core, forms, http
... platform-browser, platform-browser-dynamic
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.4 (cli-only)
@angular-devkit/build-optimizer   0.0.35
@angular-devkit/core              9.0.4 (cli-only)
@angular-devkit/schematics        9.0.4 (cli-only)
@schematics/angular               9.0.4 (cli-only)
@schematics/update                0.900.4 (cli-only)
rxjs                              5.5.2
typescript                        2.8.3
webpack                           3.12.0

我建议使用 Observables 而不是 Promises,因为 Angular 经常使用前者并且在某种程度上促进了响应式风格。

考虑以下示例代码:

@Injectable({
  providedIn: 'root'
})
export class SomeService {
  private readonly URL: string = 'someurl';

  constructor(private http: HttpClient) {}

  public loadData(): Observable<any> {
    return this.http.get(this.URL).pipe(
      // if you want to handle errors you can use the catchError operator
      // however, a better way is to use a HTTP Interceptor instead
      // if you want to see how you can handle errors with the interceptor let me 
      // know
      catchError(error => throwError(error)),
      map(res => // do some transformation if you need),
      tap(res => // add some side effects if you need)

     // don't subscribe in the service - it is considered to be a bad practice
  }
}

您可以调用组件中的方法并手动订阅它,也可以使用模板中的 async 管道自动订阅和取消订阅。

尽管取消订阅可观察对象以避免内存泄漏非常重要,Angular 会为 HttpClient 管理此操作,因此您无需手动取消订阅。

对于所有其他 Observable,您可以使用 takefirstlasttakeUntil 等运算符或将订阅存储到 属性 类型Subscription 并在 OnDestroy 生命周期挂钩中取消订阅(在调用 next 的 takeUntil 运算符和 complete/unsubscribe 其参数为 Subject 的情况下,必须执行相同的操作).

如果您想改用 Promises,可以使用 trycatch 块来处理错误。

我创建了一个 stackblitz here,其中包含了错误拦截器。

确保在应用程序模块的提供程序数组中提供拦截器,如下所示:

providers: [{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }],