typescript 认购承诺

hjqgdpho  于 2023-02-05  发布在  TypeScript
关注(0)|答案(5)|浏览(202)

在我的Angular 7应用程序中,我有下一个函数:

getUserData(uid) {
    return this.fireStore.collection('users').doc(uid).valueChanges().subscribe(data => {
      this.writeCookie(data)
      this.currentUser = data;
    })
  }

我想在另一个方法中使用这个函数:

someMethod() {
      ...
      new Promise(this.getUserData(uid))
         .then(() => {...})
      ...
   }

但是我不能这样做,因为TypeScript抛出了一个错误:
类型为"Subscription"的参数不能赋值给类型为"Subscription"的参数(解析:(值?:{}|类似承诺〈{}〉)=〉无效,拒绝:(原因?:任意)=〉void)=〉void '。类型"订阅"未提供与签名"(解析:(值?:{}|类似承诺〈{}〉)=〉无效,拒绝:(原因:任何)=〉无效):无效(2345)
如何将getUserData()方法转换为承诺,或者使用forJoin
先谢了。

mkh04yzy

mkh04yzy1#

subscribe将类型从Observable更改为Subscription,从而导致类型错误。
你可能需要把Observable转换成Promise,同时保留函数调用,你可以通过tap传输Observable,然后用toPromise转换结果,如下所示:

getUserData(uid) {
  return this.fireStore.collection('users').doc(uid).valueChanges().pipe(
    tap(data => {
      this.writeCookie(data)
      this.currentUser = data;
    }),
    first()
  ).toPromise()
}

确保创建一个完成管道,就像您可以使用first操作符所做的那样,否则Promise将永远无法解析。
您可以在消费者中省略new Promise(...)

jfewjypa

jfewjypa2#

ggradnig的实现是正确的解决方案,但是我想更深入地分析一下为什么它能工作,这样如果将来有人遇到这个问题就不会感到困惑了。
当你订阅一个观察对象时,大多数时候你只需要传入一个回调函数,这个回调函数描述了当你接收到数据流时你想要如何处理它。实际上,观察对象中可以包含3个不同的回调函数,用于不同类型的事件。它们是:
1.next-当从流中接收到数据时调用。所以如果你请求获取一些口袋妖怪的统计数据,它会调用“next”回调函数,并将数据作为输入传递。大多数时候,这是你唯一关心的数据,rxjs的创建者知道这一点,所以如果你只在订阅中包含一个回调函数,预订将默认为将“下一个”数据传递到该回调中。
1.error-非常简单明了。如果一个错误在你的可观察对象中被抛出并且没有被捕获,它将调用这个回调函数。
1.complete-当可观察对象完成时调用。
如果你想处理从一个可观察对象发出的所有不同类型的数据,你可以在订阅中编写一个观察者,如下所示:

this.http.get(“https://pokemon.com/stats/bulbasaur”).subscribe({
    next: () => { /* deal with pokemon data here */},
    error: () => {/* called when there are errors */},
    complete: () => {/* called when observable is done */}
})

在大多数情况下,这也是不必要的,但是当我们调用."toPromise“时,理解这些类型的事件是至关重要的()”的方法。当我们把一个可观察的转化为一个承诺时,所发生的事情是,一旦调用了Observable上的“Complete”方法,Promise将使用Observable发出的最后一个“next”数据进行解析。这意味着,如果“Complete”回调函数未被“如果你不打电话来,诺言就会无限期地挂起。
我知道你在想什么我一直在把我的http请求从Observables转换成Promises,我从来没有遇到过Promises无限期挂起的情况。这是因为只要从http调用中接收到所有数据,Angular http库就会调用Observable上的“Complete”回调函数。这是有意义的,因为一旦你从请求中接收到所有数据,你就完成了。你不期望将来有更多的数据。
这与问题中描述的情况不同,你正在调用firestore,我从经验中知道firestore使用套接字来传输信息,而不是http请求。这意味着通过连接你可能会接收到一组初始数据......然后更多的数据......然后更多的数据。它本质上是一个没有明确终点的流。所以它永远没有理由调用“完成”回调。同样的事情也会发生在行为和重播主题上。
为了避免这个问题,你需要强制Observable调用“Complete”回调函数,方法是通过管道输入“first()”或“take(1)”,这两种方法都是一样的,调用“next”回调函数,将初始数据集作为输入,然后调用“Complete”回调函数。
希望这是有用的人在那里,因为这个问题困惑了我很长一段时间。
此外,如果你仍然感到困惑,这个视频是一个很好的参考:https://www.youtube.com/watch?v=Tux1nhBPl_w

ebdffaop

ebdffaop3#

如果您必须在getUserData方法中具有**.subscription**,则这是另一种方法。

getUserData(uid): Promise<any> {
    return new Promise((resolve, reject) => {
        this.fireStore.collection('users').doc(uid).valueChanges().subscribe({
            next: data => {
                this.writeCookie(data)
                this.currentUser = data;
                resolve();
            },
            error: err => {
                reject(err);
            }
        });
    });
}

那么你可以这样使用

someMethod() {
    this.getUserData(uid)
        .then(() => {...
        })
        .catch(e =>{

        });
}
0yg35tkg

0yg35tkg4#

当前您正在返回整个订阅。若要修复此问题,您需要使用toPromise

getUserData(uid) {
        return this.fireStore.collection('users').doc(uid).valueChanges().toPromise()
      }

由于您正在返回上述fn中的承诺,因此无需创建新的承诺

someMethod() {
      ...
      this.getUserData(uid)
         .then(() => {...})
      ...
   }
tzcvj98z

tzcvj98z5#

您应该使用新的语法将可观察性转换为承诺:

getUserData(uid) {
        return firstValueFrom(
            this.fireStore.collection('users').doc(uid).valueChanges()
                .pipe(
                    tap(data => {
                        this.writeCookie(data)
                        this.currentUser = data;
                    })
                )
        );
    }

相关问题