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

时间:2020-03-17 23:16:59

标签: angular typescript promise observable ionic4

我简化了以下服务代码,以便在此处发布

    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的Sugar语法。

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

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

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

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

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

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

顺便说一句,即使我使用的是Promises,Observables,ReplaySubject(1),这对我来说都是中国人,也是我分心和沮丧的巨大来源,可以实现我的简单目标,即显示一些我从网络上检索到的数据或图片。 因此,如果您有一种方法/模式可以清楚地放下代码,以便当我从现在开始四个月复出时,一切都说得通:)

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

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

1 个答案:

答案 0 :(得分:2)

我建议使用Observables代替Promises,因为Angular首先使用了Observables,并且在某种程度上促进了反应式。

考虑以下示例代码:

@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生命周期挂钩中取消订阅(对于takeUntil运算符,必​​须在下一个调用并为参数Subject完成/取消订阅的情况下执行相同操作)。

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

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

确保像这样从应用程序模块在providers数组中提供拦截器:

providers: [{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }],
相关问题