3

ユーザーが自分の Google アカウントを介して自分自身を識別できるアプリケーションを作成しています。舞台裏では、gapi を使用してログインを処理しています。一方、ユーザーObservableの状態(オンライン/オフライン)が変化するたびに加入者に情報をブロードキャストする「ユーザー」と呼ばれる角度のあるサービスがあります。次に、すべてを結合するためにボタンがあり、ユーザーがそれをクリックすると、次のようになります。

  • gapi が初期化されると解決される promise が作成されます。(以下のコードの 1 行目)
  • promise が解決されると、gapi を介して Google ログインが実行されます。(以下のコードの 2 行目)
  • ログインの約束が解決されると、AJAX リクエスト ID がバックエンドに対して行われ、Google トークンが検証され、電子メール、名前などの情報が返され、このオブザーバブルにサブスクライブされます。this.restService(以下のコードの で始まる行)
  • 上記のオブザーバブルが Web サービスによって返された値を発行するとき、ユーザーのステータスのオブザーバブルの値を発行する「ユーザー」サービスの関数を呼び出します (ユーザーが現在認証されているという事実をブロードキャストします)。
  • 次に、すべてのサブスクライバーがこの情報を受け取り、ユーザーがログインしていることを認識します。

コードは次のとおりです。

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.logcanPostCommentプロパティが更新され、ビューも更新されるため、問題はありません。ただし、Web サービスに少し時間がかかるconsole.logと、正しい値が表示されますが、ビューは更新されません...

Angular の変更検出と関係があるのではないかと疑って、次のようにゾーンを使用します。

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

そして、それは機能します...だから、ゾーンについて読んで、変更検出(またはそのようなもの...)を実行する必要があることをangularに警告するために使用されていることを知りましたが、setTimeoutまたはAJAX呼び出しのような一般的な機能も読みましたすでに「ゾーン」によってモンキーパッチが適用されているため、問題がどのように解決されるのかわかりません。また、この問題が発生する理由もわかりません。canPostCommentAngularが変更を認識しないのはなぜですか?

私のコードは少し複雑なので、それを plunkr するのはかなり難しいでしょう。そのため、関連するコードのほとんどをコピーして貼り付けます。

編集

質問した後、ログイン プロセス全体がいつ完了したかを知る必要があったため、コードを少し変更する必要がありました。実際、ユーザーがログイン ボタンをクリックすると、そのキャプションが「Logging in...」になり、プロセス全体が完了すると消えます。オブザーバブルを購読することuserService.getStatusもできましたが、次のことができるという約束をすることにしました。

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