3

我正在创建一个应用程序,用户可以通过他的 Google 帐户来识别自己。在幕后,我使用 gapi 来处理登录。另一方面,有一个称为“用户”的角度服务,Observable每次用户的状态(在线/离线)发生变化时,它都会向订阅者广播信息。然后,将所有内容粘合在一起,有一个按钮,当用户单击它时,会发生以下情况:

  • 一旦 gapi 被初始化,就会创建一个 Promise 来解决。(下面代码的第一行)
  • 当 promise 解决时,Google 登录是通过 gapi 执行的。(下面代码的第二行)
  • 当登录承诺解决时,向后端发出 AJAX 请求 id 以验证 Google 令牌并返回电子邮件、姓名等信息并订阅此 observable。this.restService(下面代码中以开头的行)
  • 当上面的 observable 发出我的 web 服务返回的值时,我在我的“用户”服务中调用一个函数,该函数在 observable 上发出一个值以表示用户的状态(它广播了用户现在已通过身份验证的事实)。
  • 然后,所有订阅者都会收到此信息并知道用户已登录。

这是代码:

this.ensureApiIsLoaded().then(() => {
    this.auth.signIn().then((user) => {
        let profile = user.getBasicProfile();
        this.restService
            .post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
            .subscribe((data: IUserData) => {
                this.userService.set("data.name", "data.email", "data.picture", AuthenticationType.Google);
            });
    });
});

问题是代码有时有效,有时无效。经过一番调查,我注意到这与我的 Web 服务执行的持续时间有关。为了确保这一点,我在其中做了一个语句,在 2 秒内暂停请求的执行,在这种情况下,我的代码总是失败。但我所说的“失败”是什么意思?

在页面的某处,我有一个订阅用户服务可观察的组件:

this.userService.getStatus().subscribe(status => {
    console.log(status);
    this.canPostComment = (status == UserStatus.Online);
});

当 Web 服务执行得非常快时,我会看到console.log,然后canPostComment属性会更新,我的视图也会更新,所以没有问题。但是,当 Web 服务需要更长的时间时,我仍然看到console.log具有正确值但视图没有更新......

怀疑它与 Angular 更改检测有关,我以这种方式使用 zone:

this.ensureApiIsLoaded().then(() => {
    this.auth.signIn().then((user) => {
        let profile = user.getBasicProfile();
        this.zoneService.run(() => {
            this.restService
                .post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
                .subscribe((data: IUserData) => {
                    this.userService.set("data.name", "data.email", "data.picture", AuthenticationType.Google);
                });
        });
    });
});

然后它起作用了......所以我读到了 zone 并且我了解到它被用来警告 angular 它必须运行更改检测(或类似的东西......),但我也读到了常见的函数,如setTimeout或 AJAX 调用已经被“区域”修补了,所以我不明白它是如何解决我的问题的,我也不明白为什么我会遇到这个问题。为什么 Angular 没有看到这种canPostComment变化?

由于我的代码有点复杂,因此很难破解它,这就是我复制/粘贴大部分相关代码的原因。

编辑

在我提出问题后,我不得不修改一些代码,因为我需要知道整个登录过程何时完成。事实上,当用户点击登录按钮时,它的标题变成了“正在登录...”,一旦整个过程完成,它就会消失。我本可以订阅userService.getStatusobservable,但我决定承诺能够做到:

this.googleAuthenticationService.login.then(() => { ... });

所以我以这种方式更新了上面的代码:

return new Promise((resolve, reject) => {
    this.ensureApiIsLoaded().then(() => {
        this.auth.signIn().then((user) => {
            let profile = user.getBasicProfile();
            this.zoneService.run(() => {
                this.restService
                    .post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
                    .subscribe((data: IUserData) => {
                        this.userService.set(data.name, data.email, data.picture, AuthenticationType.Google);

                        resolve(true)
                    },
                    error => reject(false));
            });
        });
    });
});

出于好奇,我试图删除该this.zoneService.run声明只是为了看看会发生什么,结果证明它没有......所以把所有东西都放在一个承诺中似乎可以解决这个问题......但是,问题仍然存在......为什么第一个例子没有用吗?

4

0 回答 0