简体   繁体   English

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

[英]angular 9 execute subscribe in code behind synchronously

I need to run a method with 2 parameters, each parameter is gotten through some form of subscribe function.我需要运行一个带有 2 个参数的方法,每个参数都是通过某种形式的 subscribe 函数获得的。 the first is the collection which is gotten through the url from angular's page routing.第一个是从 angular 的页面路由通过 url 获取的集合。 The second is the dokument, this is the firebase's firestore document.第二个是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 populates perfectly fine; this.collection 可以很好地填充; this.dokument is only populated inside the subscribe method this.dokument 仅填充在 subscribe 方法中

I need this to be populated by the time the next line is run.我需要在下一行运行时填充它。 the console.log(this.dokument); console.log(this.dokument);

I have been dumbstruck by this because essentially the same code is used by the 2 subscribe methods but they don't behave the same way.我对此感到目瞪口呆,因为 2 种订阅方法使用的代码基本上相同,但它们的行为方式不同。

Sometimes a subscribe can be synchronous.有时订阅可以是同步的。 This happens when the Observable is a ReplaySubject a BehaviorSubject or an Observable which has a shareReplay() pipe.这种情况发生在ObservableReplaySubject一个BehaviorSubjectObservable具有shareReplay()管。 (probably other options as well. (可能还有其他选择。

This will make the observable immediately fire on subscription.这将使 observable 在订阅时立即触发。 However, you should never count on this behavior, and always continue within your subscribe.. Or use pipes like mergeMap and create other observables which you can access in your template using the async pipe.但是,您永远不应该指望这种行为,并始终在您的订阅中继续.. 或者使用像 mergeMap 这样的管道并创建其他可观察对象,您可以使用async管道在模板中访问它们。

In your case.在你的情况下。 The this.route.params is obviously a 'replaying' Observable from which you get the latest value after subscribing. this.route.params显然是一个“重播” Observable,您可以在订阅后从中获得最新值。 Otherwise you would have to wait for the params to change again until you get a value.否则,您将不得不等待参数再次更改,直到获得值。

Your Database call cannot return an immediate response, because it's essentially a network request.您的 Database 调用无法立即返回响应,因为它本质上是一个网络请求。


In your example code, you can update it to this, and use the async pipe in your template在您的示例代码中,您可以将其更新为此,并在您的模板中使用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);
    }); 
  }
}

Maybe you should make the Observable a Promise, in your case would be the following :也许你应该让 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