Angularjs 角度和全局对象
我已经读了很多关于角度承诺的书,以及如何使用它们,如何延迟,如何拒绝/解决它们,如何使用。然后,。最后,等等 现在,我正在尝试做一些可能毫无意义的事情,或者它确实有意义,我只需要在我变得比我想象的更疯狂之前检查它是否有意义以及如何做: 我有一个应用程序,我希望该应用程序有一个可以被不同控制器访问的全局对象,实际上,甚至连模板都可以访问它,我希望每个人在访问它之前都要等待对象充满数据 我已经调用了这个对象myProfile,它是我的用户,当然我希望许多控制器/模板能够访问我的用户名和配置文件详细信息,而无需一直调用任何地方,只需键入$rootscope.myProfile之类的内容 这似乎是可行的,模板等待它被填满,控制器可以访问它。。。我只需要在将应用程序加载到ProfileService.getMyUser时进行初始调用,实际上我创建了这个工厂,它创建了全局对象:Angularjs 角度和全局对象,angularjs,Angularjs,我已经读了很多关于角度承诺的书,以及如何使用它们,如何延迟,如何拒绝/解决它们,如何使用。然后,。最后,等等 现在,我正在尝试做一些可能毫无意义的事情,或者它确实有意义,我只需要在我变得比我想象的更疯狂之前检查它是否有意义以及如何做: 我有一个应用程序,我希望该应用程序有一个可以被不同控制器访问的全局对象,实际上,甚至连模板都可以访问它,我希望每个人在访问它之前都要等待对象充满数据 我已经调用了这个对象myProfile,它是我的用户,当然我希望许多控制器/模板能够访问我的用户名和配置文件详细信
function myUserProfile(ProfileService, $rootScope, $analytics) {
return ProfileService.getWhoAmI()
.then(function(user) {
$rootScope.myProfile = user;
$analytics.setUserProperties({
// blah
});
});
}
myApp.factory('myUserProfile', myUserProfile);
myApp.run(function (myUserProfile) {
// The factory will be instantiated here as has been injected
});
是的,它也有助于设置分析内容
我的问题是,如果我试图在对象填充之前访问它,我会得到一个未定义的错误:
console.log($rootScope.myProfile);
$rootScope.myProfile.testProp = 300;
console.log($rootScope.myProfile);
日志:
为了能够等待以更手动的方式填充,我可以将另一个$rootscope变量设置为promise,如:
$rootScope.myProfileRetrieved = ProfileService.getWhoAmI()
.then(function(user) {
$rootScope.myProfile = user;
});
然后我可以这样做:
$rootScope.myProfileRetrieved.then(function () {
console.log($rootScope.myProfile);
$rootScope.myProfile.testProp = 300;
console.log($rootScope.myProfile);
});
这就行了。但我不太相信这是一个好的做法,它甚至听起来有点错误
所以我的问题是,如果我想在上面写东西的话,我是否必须一直使用。然后在访问之前确保对象在那里?有没有一种方法可以满足我的要求,那就是:等到对象到达,然后不加a就写,然后一直写
我是不是完全错了,承诺不应该被这样使用
非常感谢,阅读太多的技术资料会让你的大脑因为太多的数据而崩溃
更新
好的,仔细想想,我认为我最初的想法离它应该的并不远,只是使用工厂而不是$rootscope,所以在控制器上我可以注入工厂,然后:
function myController($scope, ... , myUserProfile, someOtherService) {
someOtherService.get().then(function (data) {
myUserProfile.then(function () {
$rootscope.myProfile.newProperty = data.Whatever;
});
});
}
也许这更有意义
function myUserProfile(ProfileService, $rootScope, $analytics) {
return ProfileService.getWhoAmI()
.then(function(user) {
$rootScope.$emit('myProfile');
$rootScope.myProfile = user;
$analytics.setUserProperties({
// blah
});
});
}
然后
或
去所有相关的地方。不太优雅,但这是异步应用程序范围依赖的代价
也许这更有意义
function myUserProfile(ProfileService, $rootScope, $analytics) {
return ProfileService.getWhoAmI()
.then(function(user) {
$rootScope.$emit('myProfile');
$rootScope.myProfile = user;
$analytics.setUserProperties({
// blah
});
});
}
不是真的,不,从控制器更新$rootScope看起来不太好$rootScope很容易被误用,但在第一种情况下,它是合理的,因为它在那里得到了事件和$watch
对于更复杂的应用程序先决条件,如果应用程序基于路由控制器,则可以使用路由解析而不是app.run和init事件,我发现以下方法非常有用
app.controller('AppController', function($scope, service1) {
var initWatcher = $scope.$root.$watch('init', function (init) {
if (!init) return;
initWatcher();
console.log(service1.data);
});
});
app.factory('service1', function ($timeout) {
var service1 = {};
Object.defineProperty(service1, 'init', { enumerable: false, value: function () {
return somePromise.then(function () {
angular.extend(service1, {
data: 'data'
});
return service1;
});
}});
return service1;
});
app.run(function ($rootScope, $q, service1, service2, service3) {
service1.init().then(function (resolvedService1) {
return $q.all({
service2: service2.init(),
service3: service3.init()
});
})
.then(function (resolved) {
$rootScope.init = true;
});
});
我认为最好的办法是确保尽早初始化足够多的对象,以便能够安全地访问所需的部件。例如,$rootScope.myProfile={}和$rootScope.myProfile.testProp将是未定义的,但不会抛出错误。当你拥有用户对象时,你可以覆盖或更新空对象。这实际上是一个非常好的主意,谢谢。虽然它仍然有一些标志,因为在执行其他操作之前,我可能需要读取一些数据,但可以解决未定义的问题。此配方适用于返回空对象的服务,但对范围属性不太有用。当它们不应该返回未定义时,它们将返回未定义,嵌套对象仍将抛出错误。我不完全相信这种方法。在我的上一个示例中,我有两个请求,在我进行更改之前,我需要其中两个请求成功。因此,如果myProfile请求在otherService完成时还没有完成,它将等待它。如果userProfile在otherService完成之前完成,您的方法可能会有问题,因为emit将很快发生。如果我将其添加到范围中,我如何知道otherService完成了它的一部分?也就是说,我有2个请求,即使它们都发出,我是否需要在控制器上设置标志以知道这两个请求都成功了?->继续如果其他服务成功,我的个人资料还没有成功,我该如何等待?我认为承诺的理念正是,你可以在一个线索中添加这些,这样你就可以等到所有的承诺都成功了,然后再做一些事情。如果其他服务完成myProfile hasnt,它将等待,如果myProfile已经完成,我将不会错过发射,因为承诺将得到解决并继续。检查更新的答案,此配方有助于我消除更复杂场景中的一些承诺混乱。
$rootScope.$watch('myProfile', function (newVal) {
if (!newVal) return;
...
})
app.controller('AppController', function($scope, service1) {
var initWatcher = $scope.$root.$watch('init', function (init) {
if (!init) return;
initWatcher();
console.log(service1.data);
});
});
app.factory('service1', function ($timeout) {
var service1 = {};
Object.defineProperty(service1, 'init', { enumerable: false, value: function () {
return somePromise.then(function () {
angular.extend(service1, {
data: 'data'
});
return service1;
});
}});
return service1;
});
app.run(function ($rootScope, $q, service1, service2, service3) {
service1.init().then(function (resolvedService1) {
return $q.all({
service2: service2.init(),
service3: service3.init()
});
})
.then(function (resolved) {
$rootScope.init = true;
});
});