首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步/等待ngOninit()

异步/等待ngOninit()
EN

Stack Overflow用户
提问于 2020-08-24 20:30:51
回答 2查看 3.2K关注 0票数 2

我正在尝试使用async/await (这是第一次),我无法用它来控制自己。

我在这里做错了什么

tree.component.ts

代码语言:javascript
复制
export class TreeComponent implements OnInit {

  private routeSub: any;
  acronym: string;
  flare: any[];

  constructor(
    private location: Location,
        private route: ActivatedRoute,
        private http: HttpClient,
        private router: Router,
        private fileTreeService: FileTreeService
  ) {


  }
  ngOnInit(): void {
      this.routeSub = this.route.params.subscribe(
        params => {
            this.acronym = params.name
            this.fileTreeService.getFileTree(params.name).subscribe(item => {
                this.flare = item;

            });
        });

filetree.service.ts

代码语言:javascript
复制
export class FileTreeService {

    res: any;

    constructor(private http: HttpClient) { }



    async getFileTree(acronym) {
        const headers = new HttpHeaders()
        this.res = await this.http.get<any>(`${IP}/filetree/tree/`, { headers });
        return this.res;
    }
}

我得到错误“属性‘’订阅‘不存在类型’承诺‘”在filetree.component.ts。我已经到了这条路的尽头,所以我要联系你们。提前谢谢。

更新:

谢谢你的帮助,它确实奏效了,但它并没有达到我想要达到的效果。难道不应该在继续执行代码之前等待结果吗?

代码语言:javascript
复制
  ngOnInit(): void {
      this.routeSub = this.route.params.subscribe(async (params) => {
            this.acronym = params.name
            this.flare = await this.fileTreeService.getFileTree(params.name).toPromise();
            console.log("flare = ", this.flare);
        });

    let test = this.flare;
    console.log("test = ", test);
} 

根在flare被赋予一个值之前声明。这就是我的浏览器控制台发出的信息。

代码语言:javascript
复制
test =  undefined
flare =  {name: "data", children: Array(81)}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-24 20:45:44

异步/等待承诺工作,因此,如果您使用httpClinet方法,您需要将返回值从可观察到的转换为通过toPromise方法承诺

filetree.service.ts

代码语言:javascript
复制
export class FileTreeService {
    res: any;

    constructor(private http: HttpClient) { }

    getFileTree(acronym) {
        const headers = new HttpHeaders()
        // return an observable 
        return  this.http.get<any>(`${IP}/filetree/tree/`, { headers })    
   }
}

组件

代码语言:javascript
复制
  ngOnInit(): void {
      //  mark the upper function with async
      this.routeSub = this.route.params.subscribe(async (params) => {  
        this.acronym = params.name;
        //  now we can use await but we need to convert the observable to promise 
        this.flare = await this.fileTreeService.getFileTree(params.name).toPromise();
        });
}

您可以深入阅读教程https://javascript.info/async-await

更新的

我们可以使用异步标记ngOnInit,并在将主题转换为承诺之后使用等待所有的观察,在这种情况下,我们将不再使用订阅。

代码语言:javascript
复制
  //  mark the upper function with async
  async ngOnInit(): Promise<void> {
    //  now we can use await but we need to convert the observable to promise 
    this.acronym = (await this.route.params.toPromise()).name;
    this.flare = await this.fileTreeService.getFileTree(this.acronym).toPromise();
    let test = this.flare;  // => {name: "data", children: Array(81)}
    console.log("test = ", test); // => {name: "data", children: Array(81)}

  }
票数 5
EN

Stack Overflow用户

发布于 2020-08-24 21:38:47

如果您是异步/反应性编程新手,我建议您不要将承诺和可观察性混为一谈。由于您使用的是角HttpClient模块,它返回一个可观察到的HTTP请求,所以我们只能继续使用它。

因此,您可以直接返回HTTP请求,而无需将其转换为承诺。Sidenote:与承诺相比,可观测数据还提供了对数据流和数据转换操作符的更多控制。

服务

代码语言:javascript
复制
export class FileTreeService {
  res: any;

  constructor(private http: HttpClient) { }

  getFileTree(acronym): Observable<any> {      // <-- `http.get()` returns an observable
    const headers = new HttpHeaders();
    return this.http.get<any>(`${IP}/filetree/tree/`, { headers });
  }
}

此外,现在您可以从this.fileTreeService.getFileTree()函数中观察到一个子函数,它依赖于来自另一个可观察到的this.route.params的通知。

在这种情况下,您可以使用RxJS高级映射操作符(如switchMap )从一个可观察到的映射到另一个,而不是像您正在做的那样具有多个内部订阅。现在,代码中的两个不同的数据流被简化为一个单一的数据流。流越小,潜在的内存泄漏越少。

组件

代码语言:javascript
复制
import { Subject } from 'rxjs';
import { switchMap, takeUntil } from 'rxjs/operators';

export class TreeComponent implements OnInit, OnDestroy {
  private routeSub: any;
  acronym: string;
  flare: any[];
  complete$ = new Subject<any>();     // <-- use to close open subscriptions

  constructor(
    private location: Location,
        private route: ActivatedRoute,
        private http: HttpClient,
        private router: Router,
        private fileTreeService: FileTreeService
  ) { }
 
  ngOnInit(): void {
    this.routeSub = this.route.params.pipe(
      switchMap(params => {           // <-- use `switchMap` to map from one observable to another
        this.acronym = params.name;
        return this.fileTreeService.getFileTree(params.name);
      }),
      takeUntil(this.complete$)       // <-- close the subscription when `this.complete$` emits
    ).subscribe(
      item => {
        this.flare = item;
        console.log(this.flare);      // <-- correct log: will print the value of `this.flare`
      },
      error => {
        // always good practice to handle errors from HTTP requests
      }
    );

    console.log(this.flare);          // <-- wrong log: will print `undefined`
  }

  ngOnDestroy() {
    this.complete$.next();            // <-- close open subscriptions
  }
}

还请记住,由于this.flare变量是异步分配的,因此依赖它的所有语句都必须在订阅中。上面的代码使用不同的console.log()语句说明了这一点。订阅内部的订阅将打印正确的值,而订阅外的订阅将错误地打印this.flare持有的未定义的或旧的值。

我还使用RxJS takeUntil操作符关闭ngOnDestory()钩子中打开的订阅。您可以找到有关它的更多详细信息,以及处理未订阅这里的其他更简单的方法。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63568331

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档