Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular NgZone是如何解决这个问题的?_Angular_Zone_Zonejs - Fatal编程技术网

Angular NgZone是如何解决这个问题的?

Angular NgZone是如何解决这个问题的?,angular,zone,zonejs,Angular,Zone,Zonejs,我正在创建一个应用程序,用户可以通过他的谷歌帐户识别自己。在幕后,我使用gapi来处理登录。另一方面,有一种称为“用户”的角度服务,它具有一个可观察的,每当用户的状态(在线/离线)改变时,它都向订户广播信息。然后,要将所有内容粘合在一起,有一个按钮,当用户单击它时,会发生以下情况: 创建一个承诺,该承诺在gapi初始化后解析。(下面代码的第1行) 当承诺解决时,Google登录将通过gapi执行。(下面代码的第二行) 当登录承诺得到解决时,会向后端发出一个AJAX请求id,以验证Google令

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

  • 创建一个承诺,该承诺在gapi初始化后解析。(下面代码的第1行)
  • 当承诺解决时,Google登录将通过gapi执行。(下面代码的第二行)
  • 当登录承诺得到解决时,会向后端发出一个AJAX请求id,以验证Google令牌,并返回电子邮件、名称等信息,并订阅此可观察内容。(以下代码中以
    this.restService
    开头的行)
  • 当上面的observable发出web服务返回的值时,我在“user”服务中调用一个函数,该函数在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服务执行得非常快时,我会看到
console.log
,然后更新
canPostComment
属性,我的视图也会更新,因此不会出现问题。但是,当web服务花费的时间稍长时,我仍然可以看到
console.log
具有正确的值,但是视图没有更新

我怀疑它与角度变化检测有关,所以我使用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);
                });
        });
    });
});
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.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);
                });
        });
    });
});
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));
            });
        });
    });
});
返回新承诺((解决、拒绝)=>{
此.ensureApiIsLoaded()。然后(()=>{
this.auth.sign().then((用户)=>{
让profile=user.getBasicProfile();
this.zoneService.run(()=>{
这是我们的服务
.post(“/api/security/authenticate”,{type:AuthenticationType.Google,token:user.getAuthResponse().id_token})
.订阅((数据:IUserData)=>{
this.userService.set(data.name、data.email、data.picture、AuthenticationType.Google);
解析(真)
},
错误=>拒绝(错误));
});
});
});
});

出于好奇,我试图删除
this.zoneService.run
语句,只是想看看会发生什么,结果发现它在没有。。。所以把一切都放在一个承诺里似乎可以解决问题。。。然而,问题仍然存在。。。为什么第一个示例不起作用?

我没有完整的答案,但这篇博文对区域进行了很好的解释:。Angular钩住Zone.js,在每个VM回合之后(即,在任何单个任务以及所有后续微任务完成之后)运行更改检测循环。该区域由角度控制。如果您在更改检测周期内进行更改(即,
ApplicationRef.tick()
在堆栈中),则您尚未开始新任务,更改检测将不会重新运行。你可以检查一下这篇文章来了解发生了什么。呵呵,这就是我在作品中提到的那篇文章。但我会再看一遍,也许我遗漏了什么。而且,很有可能它没有在Angular的范围内运行儿童承诺。我不知道为什么不这样做,但以防万一你可以考虑链接你的承诺而不是创建子承诺:<代码> .EnSuxRiPiSoLoDeD()。然后(()=这个。Auth.Suin())。然后((用户)= {{…});
能否在
控制台.log(状态)之后添加以下内容语句
console.log('Zone is:',Zone.current.name)?嗨,“区域”对象来自哪里?我尝试注入NgZone 1,但其中没有“当前”属性。然而,通过尝试这样做,我注意到,如果我把所有事情都写进一个承诺中,我就不再需要这个区域了。事实上,我更新了代码,以了解整个过程何时完成,因此我在其周围添加了
新承诺…
,现在,当我删除
区域。运行
部分时,无论我的web服务花费多少时间,它都能工作。。。我会更新OP。