Почему NgZone решает эту проблему?

Я создаю приложение, в котором пользователь может идентифицировать себя через свою учетную запись Google. За кулисами я использую gapi для обработки логина. С другой стороны, есть угловой сервис, называемый "пользователь", который имеет Observable это передача информации подписчикам каждый раз, когда изменяется статус (онлайн / оффлайн) пользователя. Затем, чтобы склеить все вместе, есть кнопка, и когда пользователь нажимает на нее, вот что происходит:

  • Создается обещание, которое разрешается после инициализации гапи. (1-я строка кода ниже)
  • Когда обещание разрешается, вход в Google осуществляется через gapi. (2-я строка кода ниже)
  • Когда обещание входа в систему разрешается, в бэкэнд делается идентификатор запроса AJAX, чтобы проверить токен Google и вернуть такую ​​информацию, как адрес электронной почты, имя и т. Д., И подписаться на это наблюдаемое. (строка, начинающаяся с this.restService в коде ниже)
  • Когда наблюдаемое выше испускает значение, возвращаемое моим веб-сервисом, я вызываю функцию в моем "пользовательском" сервисе, которая выдает значение наблюдаемого для статуса пользователя (оно передает факт, что пользователь теперь аутентифицирован).
  • Затем все подписчики получают эту информацию и знают, что пользователь вошел в систему.

Вот код:

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

Дело в том, что код иногда работает, а иногда нет. После некоторого расследования я заметил, что это было связано с продолжительностью выполнения моего веб-сервиса. Чтобы убедиться в этом, я сделал внутри него заявление, которое приостанавливает выполнение запроса на 2 секунды, и в этом случае мой код всегда дает сбой. Но что я имею в виду под "неудачами"?

Где-то на странице у меня есть компонент, который подписан на наблюдаемый пользовательский сервис:

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

Когда веб-служба выполняется очень быстро, я вижу console.logтогда canPostComment Свойство обновляется и мой взгляд, так что нет проблем. Тем не менее, когда веб-служба занимает немного больше времени, я все еще вижу console.log с правильным значением, но представление не обновляется...

Подозревая, что это как-то связано с обнаружением угловых изменений, я использую зону следующим образом:

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 уже пропатчен "зоной", поэтому я не понимаю, как он решает мою проблему, и я не понимаю, почему у меня есть эта проблема. Почему Angular этого не видит canPostComment изменилось?

Так как мой код немного сложен, его было бы довольно сложно запрограммировать, поэтому я копирую / вставляю большую часть соответствующего кода.

РЕДАКТИРОВАТЬ

После того, как я задал вопрос, мне пришлось немного изменить свой код, потому что мне нужно было знать, когда завершится весь процесс входа в систему. Действительно, когда пользователь нажимает кнопку входа в систему, его заголовок становится "Вход в систему..." и после завершения всего процесса он исчезает. Я мог бы подписаться на 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 заявление, чтобы увидеть, что происходит, и оказывается, что это работает без... Итак, все в обещании, кажется, решает проблему... Однако вопрос все еще остается... Почему первый пример не сработал?

0 ответов

Другие вопросы по тегам