簡體   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