如何在 ngOnInit 中使用 await/async?

4
我正在尝试在ngOnInit() 中调用一个函数,并向其提供两个值。所以这是我试图在ngOnInit内部调用的函数: this.complexWordIdentification(this.postIWant, this.theHardWords); 问题在于,如您下面所看到的,this.postIWantthis.theHardWordsngOnInit中被解析,导致错误。那么,如何调用this.complexWordIdentification(this.postIWant, this.theHardWords);并向它提供这些值而不出错呢?
我一直在思考使用await函数吗?但我无法弄清楚,请给予任何建议?
这是我的ngOnInit:
ngOnInit() {
    this.isLoading = true;
    this.wordsLoaded = false;
    this.postLoaded = false;
    this.form = new FormGroup({
      annotation: new FormControl(null, {
        validators: [
          Validators.required,
          Validators.minLength(8),
          Validators.maxLength(250)
        ]
      })
    });
    this.id = this.route.snapshot.paramMap.get('postId');
    this.annotationService.getWords();
    this.annotationSub = this.annotationService
      .getWordUpdateListener()
      .subscribe((thewords: ComplexWord[]) => {
        this.thewords = thewords;
        this.thewords.map(word => {
          this.theHardWords.push(word.word);
          this.wordWithAnnotation.push(word);
        });
        this.wordsLoaded = true;
        this.isLoading = this.postLoaded && this.wordsLoaded;
      });
    this.postsService.getPosts();
    this.postsSub = this.postsService
      .getPostUpdateListener()
      .subscribe((posts: Post[]) => {
        this.posts = posts;
        this.posts.map(post => {
          if (post.id === this.id) {
            this.postIWant = post.fileText;
          }
        });
        this.postLoaded = true;
        this.isLoading = !(this.postLoaded && this.wordsLoaded);
      });
    this.role = this.authService.getUserRole();
    this.userIsAuthenticated = this.authService.getIsAuth();
    this.authStatus = this.authService
      .getAuthStatus()
      .subscribe(isAuthenticated => {
        this.userIsAuthenticated = isAuthenticated;
        this.role = this.authService.getUserRole();
      });
}

如果有人能指导我方向,那就太好了,因为我在这个领域并不是很有经验。目前,我必须在ngOnInit之外调用this.complexWordIdentification(this.postIWant, this.theHardWords);来避免错误,但显然,我希望自动调用它。


我认为你可以使用Observable.forkJoin()来完成你想要做的事情。 - Calidus
@Calidus,关于如何使用fork.join()有什么建议吗?我以前从未使用过,谢谢。 - Andrew
3个回答

6

forkJoin将两个订阅合并为一个,并返回它们的结果数组。当你需要在加载组件之前从多个来源获取数据时,在ngOnInit中使用它非常有用。

https://www.learnrxjs.io/operators/combination/forkjoin.html

import { Observable } from "rxjs/Observable";
    Observable.forkJoin(
        this.annotationService.getWordUpdateListener(),
        this.postsService.getPostUpdateListener()
    ).subscribe((data) => {
         // data[0] result from getWordUpdateListener
         this.thewords = data[0];
            this.thewords.map(word => {
              this.theHardWords.push(word.word);
              this.wordWithAnnotation.push(word);
            });
            this.wordsLoaded = true;

         // data[1] result from getPostUpdateListener
         this.posts.map(post => {
              if (post.id === this.id) {
                this.postIWant = post.fileText;
              }
            });
            this.postLoaded = true;
        this.isLoading = false;
        this.complexWordIdentification(this.postIWant, this.theHardWords);
    }, (err) => {
        // error handling
    });

编辑:在RXJS 5及以下版本中添加Observable的导入语句

编辑:RXJS 6更新,更改了导入语句

import { forkJoin} from 'rxjs';
forkJoin(this.annotationService.getWordUpdateListener(),
            this.postsService.getPostUpdateListener()
).subscribe((data) => { \\do stuff}, (err) => { \\ do error stuff}

编辑2:RXJS更改了forkJoin的签名,现在它接受一个数组。
    forkJoin([this.annotationService.getWordUpdateListener(),
            this.postsService.getPostUpdateListener()]
).subscribe((data) => { \\do stuff}, (err) => { \\ do error stuff}

类型 'typeof Observable' 上不存在属性 'forkJoin'。我已经导入了 Observable 和 forkJoin。 - Andrew
1
你将要从rxjs中导入它,我已经更新了我的帖子。 - Calidus
它似乎无法通过订阅部分,没有错误,只是无法通过,有什么建议吗? - Andrew
1
你是不是没有从forkJoin中获取到数据?或者你在处理数据时遇到了麻烦。 - Calidus
1
记录或检查数据中的值。这将告诉您问题是出在forkJoin还是数据处理方式上。 - Calidus
显示剩余5条评论

1

因为您需要同时来自两个不同流的数据,所以您需要以某种方式将这些流合并。以下是一个示例,说明如何实现:

this.annotationService.getWordUpdateListener().pipe(
  switchMap(thewords => {
    return this.postsService.getPostUpdateListener().pipe(
      map(posts => ({ thewords, posts }))
    );
  }),
)
.subscribe(({ thewords, posts }) => {
  this.complexWordIdentification(posts, thewords);
});

如果我能解决这个问题,我会回来的。谢谢。 - Andrew
似乎仍在加载 this.postIWantthis.theHardWords 之前就调用它了。 - Andrew
1
删除计算这些变量的功能,并将其全部放在上述订阅中。 - jcroll
1
这里的想法是不要在两个不同的地方计算这些数据,而是合并两个可观测值,在一个地方进行计算。 - jcroll
我这样做对吗?下面是我所更改的内容:.subscribe(({ thewords, posts }) => { this.posts.map(post => { if (post.id === this.id) { this.postIWant = post.fileText; } }); this.thewords.map(word => { this.theHardWords.push(word.word); this.wordWithAnnotation.push(word); }); this.complexWordIdentification(posts, thewords); }); - Andrew

1
如果你需要在组件初始化时同时使用this.postIWant和this.theHardWords,你可以考虑使用Angular Resolve,即https://angular.io/api/router/Resolve 例如:
class Backend {
  fetchTeam(id: string) {
    return 'someTeam';
  }
}

@Injectable()
class TeamResolver implements Resolve<Team> {
  constructor(private backend: Backend) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<any>|Promise<any>|any {
    return this.backend.fetchTeam(route.params.id);
  }
}

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamCmp,
        resolve: {
          team: TeamResolver
        }
      }
    ])
  ],
  providers: [TeamResolver]
})
class AppModule {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接