角9执行同步在代码后面订阅

时间:2020-02-22 12:27:33

标签: javascript angular firebase google-cloud-firestore angularfire2

我需要运行一个带有2个参数的方法,每个参数都是通过某种形式的订阅函数获得的。第一个是从angular的页面路由通过url获得的集合。第二个是文档,这是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仅填充在subscription方法内部

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

这让我很困惑,因为2个订阅方法使用了基本上相同的代码,但是它们的行为方式不同。

2 个答案:

答案 0 :(得分:0)

有时订阅可以是同步的。当ObservableReplaySubjectBehaviorSubject或具有Observable管道的shareReplay()时,就会发生这种情况。 (可能还有其他选择。

这将使可观察的对象立即在订阅时触发。但是,您永远不要指望这种行为,并且始终在订阅中继续。。或者使用诸如mergeMap之类的管道并创建其他可观察对象,您可以使用async管道在模板中对其进行访问。

以您为例。 this.route.params显然是一个“正在重放”的可观察对象,您可以在订阅后从中获得最新值。否则,您将不得不等待参数再次更改,直到获得值为止。

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


在示例代码中,您可以对其进行更新,并在模板中使用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);
    }); 
  }
}

答案 1 :(得分:0)

也许您应该将“可观察到的”作为一个承诺,具体如下:

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);
  });
 }

}