繁体   English   中英

angular 9 在后面的代码中同步执行订阅

[英]angular 9 execute subscribe in code behind synchronously

我需要运行一个带有 2 个参数的方法,每个参数都是通过某种形式的 subscribe 函数获得的。 第一个是从 angular 的页面路由通过 url 获取的集合。 第二个是dokument,这是firebase 的firestore 文件。

export class FirebaseDocument implements OnInit {
   collection: string;
   dokument: any;

   //== CONSTRUCTORS
  constructor(
    private route: ActivatedRoute,
    private _db: AngularFirestore
  ) {}

  //== Initialize
  ngOnInit() {
    console.log("__loading page component");
    this.route.params.subscribe(params => {
      this.collection = params["collection"];
    });
    console.log(this.collection);//collection populated correctly

    //load the document from AngularFirestore
    console.log("loading the document from firebase");
    let itemsCollection = this._db.collection(url).valueChanges();
    
    //subscribe to get the dok of the first document in the collection
    itemsCollection.subscribe(docArr => {
        this.dokument = docArr[0];
        console.log(this.dokument);//dokument is populated
    });
    
    console.log(this.dokument);//dokument is undefined
    this.doMultiParameterMethod(this.collection, this.dokument);
  }
}

this.collection 可以很好地填充; this.dokument 仅填充在 subscribe 方法中

我需要在下一行运行时填充它。 console.log(this.dokument);

我对此感到目瞪口呆,因为 2 种订阅方法使用的代码基本上相同,但它们的行为方式不同。

有时订阅可以是同步的。 这种情况发生在ObservableReplaySubject一个BehaviorSubjectObservable具有shareReplay()管。 (可能还有其他选择。

这将使 observable 在订阅时立即触发。 但是,您永远不应该指望这种行为,并始终在您的订阅中继续.. 或者使用像 mergeMap 这样的管道并创建其他可观察对象,您可以使用async管道在模板中访问它们。

在你的情况下。 this.route.params显然是一个“重播” Observable,您可以在订阅后从中获得最新值。 否则,您将不得不等待参数再次更改,直到获得值。

您的 Database 调用无法立即返回响应,因为它本质上是一个网络请求。


在您的示例代码中,您可以将其更新为此,并在您的模板中使用async管道

export class FirebaseDocument implements OnInit {
   readonly collection$: Observable<string> = this.route.params.pipe(
     map((params) => params.collection)
   );

   readonly doc$: Observable<any[]> = this.db.collection(this.url).valueChanges().pipe(
     shareReplay({ refCount: true, bufferSize: 1 })
   );

   constructor(private route: ActivatedRoute, private db: AngularFirestore) {}

  ngOnInit() {
    // don't forget to unsubscribe
    combineLatest([
      this.collection$,
      this.doc$
    ]).subscribe((collection, document) => {
      this.doMultiParameterMethod(collection, document);
    }); 
  }
}

也许你应该让 Observable 成为一个 Promise,在你的情况下是这样的:

export class FirebaseDocument implements OnInit {
 collection: string;
 dokument: any;

 //== CONSTRUCTORS
 constructor(
  private route: ActivatedRoute,
  private _db: AngularFirestore
 ) {}

 //== Initialize
 ngOnInit() {
  console.log("__loading page component");
  this.route.params.subscribe(params => {
   this.collection = params["collection"];
  });

  console.log(this.collection); //collection populated correctly

  this.getDokument().then(docArr => {
   this.dokument = docArr[0];
   this.doMultiParameterMethod(this.collection, this.dokument);
  });

 }

 getDokument(): Promise<any> {
  let itemsCollection = this._db.collection(url).valueChanges();
  return new Promise((resolve, reject) => {
   itemsCollection.subscribe((response: any) => {
    resolve(response);
   }, reject);
  });
 }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM