当运行块中存在无限循环时,工厂中的 $http 成功回调未运行
Posted
技术标签:
【中文标题】当运行块中存在无限循环时,工厂中的 $http 成功回调未运行【英文标题】:$http success callback in factory not running when there's an infinite loop in run block 【发布时间】:2015-11-01 06:31:43 【问题描述】:这是我的代码以及相关部分bolded:
authorization.js
有角度的 .module('mean-starter') 。跑跑); 功能运行($rootScope,身份验证,$state) $rootScope.$on('$stateChangeStart', function(event, toState, toParams) if (typeof toState.authenticate !== 'undefined') var currentUser = Auth.getCurrentUser(); 而(!currentUser._id) var isAdmin = currentUser.role === 'admin'; var isAuthorized = currentUser._id.toString() === toParams.id; if (!Auth.isLoggedIn()) event.preventDefault(); alert('必须登录才能访问此路由。'); $state.go('登录'); 否则如果(toState.authenticate.authorized) if (!isAdmin && !isAuthorized) event.preventDefault(); alert('您无权访问该路由。'); 否则如果(toState.authenticate.isAdmin) 如果(!isAdmin) event.preventDefault(); alert('您必须是管理员才能访问此路由。'); );auth.factory.js
有角度的 .module('mean-starter') .factory('Auth', function($http, $state, $window, $cookies) console.log('factory cb'); var currentUser = ; if ($cookies.get('userId')) console.log('userId'); $http .get('/当前用户') .成功(功能(数据) console.log('成功'); angular.copy(data, currentUser); ) .error(函数() console.log('获取当前用户的问题'); ); 返回 注册:功能(用户) return $http.post('/users', 用户) .success(函数(数据、状态、标头、配置) angular.copy(数据,当前用户); $cookies.put('userId', data._id); $window.location.href = '/'; ); , 登录:功能(用户) 返回 $http .post('/登录', 用户) .成功(功能(数据) angular.copy(数据,当前用户); $cookies.put('userId', data._id); $window.location.href = '/'; ); , 注销:函数() $http .get('/注销') .成功(函数() angular.copy(, currentUser); $cookies.remove('userId'); $window.location.href = '/'; ) .error(函数() console.log('退出问题。'); ); , getCurrentUser: 函数() 返回当前用户; , isLoggedIn:函数() 返回 !!currentUser._id; ; );我的问题是,如果没有 while
循环,我会收到此错误:
Cannot read property 'toString' of undefined
它指的是currentUser._id
是undefined
,而我试图打电话给toString
。我的理解是Auth.getCurrentUser()
最初返回对 的引用。然后赋值语句将
赋值给
currentUser
,代码继续执行。当响应返回时,它应该更新,因此应该“更新”
currentUser
,因为currentUser
指向一个更新的对象。
如果这是真的,我的问题是可以理解的,因为它试图在响应返回之前执行currentUser._id.toString()
。所以我试图做的是把while
循环放在那里,基本上暂停执行,直到响应回来。但是while
循环无限运行!响应最终不应该回来吗,更新currentUser
,当它出现时,!currentUser._id
应该是false
,并且循环应该中断?
第一个 factory cb
已注销。然后userId
被注销。到目前为止,一切都很好。但随后无限循环开始,success
永远不会被注销。请求不应该是异步的吗? while
循环如何阻止它?这是怎么回事?
通话没有问题。如果没有while
循环,它会触发成功回调并记录success
。此外,如果我在authorization.js
中console.dir(currentUser)
它给了我用户,但如果我console.log(currentUser)
给我一个空对象。不知道为什么会这样。
【问题讨论】:
while 循环不会暂停执行。有关循环和范围的更多信息,请参阅此处:***.com/questions/18465211/… @livepo 如果while
循环没有暂停执行,那么问题出在哪里?
在您的 ajax 调用返回信息之前,您的代码正在执行。您放入了一个while循环来停止执行,但是while循环不会停止执行(代码是异步的)。当您声明 currentUser = Auth.getCurrentUser 时,据我所知,您是按值传递。 currentUser 的值永远不会改变,因此循环将继续运行。有关参考与价值的信息,请参阅本文:***.com/questions/7744611/…
@livepo 它通过引用传递。 console.dir(currentUser)
有效。如果它通过值传递
,currentUser
将永远不会得到更新。它也适用于我的代码的其他部分。
什么也适用于其他部分?你能给我们举个例子说明它在哪里工作吗?
【参考方案1】:
Angular 服务是单例的,这意味着它们只创建一次,第一次需要它们,然后同一个对象作为依赖项在这里和那里传递。这意味着获取当前用户的代码只运行一次。如果您的用户没有登录会发生什么?什么都没有。
由于您使用 cookie,您可以在需要当前用户 (getCurrentUser) 时执行以下操作,您应该查看数据是否存储在 cookie 中,如果是,则继续执行您的代码。如果当前用户为空,那么您没有登录,您应该查询您的 API 以获取数据。这意味着您应该在 Promise 中运行代码。
由于您在用户登录和查询 API 时运行的代码是相同的,因此您应该将该代码移到服务中以便可重用。
此外,每次用户登录、注销等时,最好广播一个事件并让应用程序中需要此信息的部分监听它并执行所需的任何操作。
【讨论】:
【参考方案2】:AFAIK,由于 javascript 是单线程的,当线程在 while 循环中旋转时,http 回调将不会获得 CPU 时间来处理响应。
【讨论】:
我同意,这绝对是不是处理异步方法的方式。 我应该知道的!我什至花时间让this“略读”了一个充分解释它的演讲。【参考方案3】:似乎正在发生的事情是您的 Auth 内容都在异步检查(这是有道理的,因为它必须进行 HTTP 调用,这不是即时的)
所以在脚本运行时,Auth.getCurrentUser()
的结果,即currentUser
对象,并没有填充您尝试访问的数据,因为它是在这一行写入的:
angular.copy(data, currentUser);
这确实在异步块内。所以发生的事情是_id
可能还不是currentUser
上的属性,所以你实际上是在undefined
上调用toString()
。
您的解决方案可能是使用回调或承诺。如果您是auth.factory.js
的作者,您可能会考虑做的不是在getCurrentUser
中同步返回对象,而是在HTTP 请求完成时返回一个promise 或一个回调。
编辑:这也是脚本中的console.dir
不会返回任何内容的原因,因为在它运行时,它不会填充任何数据。
【讨论】:
我是auth.factory.js
的作者。我这样写的原因是我可以从多个地方数据绑定到当前用户。
还是可以的;使用 getter 和 setter以上是关于当运行块中存在无限循环时,工厂中的 $http 成功回调未运行的主要内容,如果未能解决你的问题,请参考以下文章
当用户未登录时,Servlet 过滤器在无限重定向循环中运行