Javascript UI路由器的角度服务异步单例
我正在使用一个角度的应用程序。我通过一个Javascript UI路由器的角度服务异步单例,javascript,angularjs,asynchronous,angular-ui-router,Javascript,Angularjs,Asynchronous,Angular Ui Router,我正在使用一个角度的应用程序。我通过一个$http异步调用获取数据,该调用用于创建各种连接对象。我的目标是有一些方法来创建这个对象,并使它作为一个单例可用。虽然发生这种情况的可能性很小,但我希望避免在异步分配服务中的socket属性时出现计时问题。当路由器中的不同状态想要获取或创建另一个连接对象时,它将通过单例来获取或创建另一个连接对象,以便可以使用相同的连接,而不是创建另一个连接 下面是我正在尝试使用的一些代码的框架。我不确定是否可以用状态的resolve做些什么 关于如何做到这一点,有什么想
$http
异步调用获取数据,该调用用于创建各种连接对象。我的目标是有一些方法来创建这个对象,并使它作为一个单例可用。虽然发生这种情况的可能性很小,但我希望避免在异步分配服务中的socket
属性时出现计时问题。当路由器中的不同状态想要获取或创建另一个连接对象时,它将通过单例来获取或创建另一个连接对象,以便可以使用相同的连接,而不是创建另一个连接
下面是我正在尝试使用的一些代码的框架。我不确定是否可以用状态的resolve
做些什么
关于如何做到这一点,有什么想法或建议吗
var myapp = angular.module('me', ['ui.router'])
.service('connectionService', ['$http', function($http) {
var socket;
// Somehow call and store result of $http in a singleton
// Would the $http.get get put in some kind of function? If so, how should it get called
// and returned so that a user of the service can get the 'socket' object synchronously?
$http.get("something/that/returns/data")
.success(function (result) {
this.socket= createConnection(result.data);
})
.error(function (err) {
//handle error
})
var getSocket= function() {
if (!this.socket) {
return createNewSocket();
} else {
return this.socket;
}
}
}])
myapp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("home");
$stateProvider
.state('home', {
url: "/home",
templateUrl: "home.html",
resolve: {
socket: // ??? Can something be done here ???
},
controller: function(socket) {
// I can haz socket?
}
})
.state('nextState', {
url: "/next",
templateUrl: "next.html",
resolve: {
socket: // Should be the same socket object as from the home state
},
controller: function(socket) {
// I can haz same socket?
}
})
})
更新 在试图更好地解释这个问题的过程中,我已经多次更改了原始代码。人们留下的评论纠正了我所犯的明确错误。我已经将上面的代码恢复到原来的状态,并在下面添加了新代码。我仍然面临的问题是,在进入控制器之前,ui路由器状态上的
resolve
没有解决。因此,在对应该解析的socket
对象调用emit()
时,出现错误“无法读取未定义的属性'emit'。我还希望socket
对象在状态之间是相同的对象。如果有任何其他建议或意见可以引导我朝着正确的方向前进,我将不胜感激
var myapp = angular.module('me', ['ui.router'])
.service('connectionService', ['$http', function($http) {
var socket;
// Somehow call and store result of $http in a singleton
// Would the $http.get get put in some kind of function? If so, how should it get called
// and returned so that a user of the service can get the 'socket' object synchronously?
$http.get("something/that/returns/data")
.then(function (result) {
socket = createConnection(result.data);
}, function (err) {
// handle error
});
var getSocket = function() {
if (!socket) {
// handle error
} else {
return socket;
}
}
}])
myapp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("home");
$stateProvider
.state('home', {
url: "/home",
templateUrl: "home.html",
resolve: {
socket: function(connectionService) {
return connectionService.getSocket();
}
},
controller: function(socket) {
socket.emit("some msg");
}
})
.state('nextState', {
url: "/next",
templateUrl: "next.html",
resolve: {
socket: function(connectionService) {
return connectionService.getSocket();
}
},
controller: function(socket) {
socket.emit("some other msg");
}
})
})
更新2 这是一个可行的解决方案,但这并不像人们所接受的正确答案那样优雅 我考虑创建自己的承诺,并将其作为ui路由器需要解决的问题返回。根据我所有的调试和堆栈跟踪,在状态之间只创建了一个连接,进入控制器的操作被延迟,直到连接被解析。因此,我相信这是一个有效的解决方案。我还有一个版本的代码,在解析承诺之前处理连接上的
onConnect
事件,但为了简洁起见,我省略了它
var myapp = angular.module('me', ['ui.router'])
.service('connectionService', ['$http', '$q', function($http, $q) {
var socket;
this.getSocket = function() {
if (!socket) {
var deferred = $q.defer();
$http.get("something/that/returns/data")
.then(function (result) {
socket = createConnection(result.data);
deferred.resolve(socket);
}, function (err) {
// handle error
deferred.reject(socket);
});
return deferred.promise;
} else {
return socket;
}
}
}])
myapp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("home");
$stateProvider
.state('home', {
url: "/home",
templateUrl: "home.html",
resolve: {
socket: function(connectionService) {
return connectionService.getSocket();
}
},
controller: function(socket) {
socket.emit("some msg");
}
})
.state('nextState', {
url: "/next",
templateUrl: "next.html",
resolve: {
socket: function(connectionService) {
return connectionService.getSocket();
}
},
controller: function(socket) {
socket.emit("some other msg");
}
})
})
据我所知,每次套接字实例无效时,您都希望根据
$http.get
中的数据初始化套接字,但在应用程序加载时异步初始化
.service('connectionService', ['$http', '$q', function($http, $q) {
//For caching the socket
var socket;
//Do the first get
tryGetData();
//tryGetData executes $http.get and returns a promise that when fulfilled -
//returns the new socket instance.
function tryGetData(){
return $http.get("something/that/returns/data")
.then(function (result) {
return socket = createConnection(result.data);
}, function (err) {
// handle error
});
}
//Whenever getSocket gets called, it first checks if the socket is instantiated. if not -
//assumes the $http.get failed and tries again to instantiate the socket calling
//$http.get again in the process.
//this function returns a promise for controllers to rely on.
this.getSocket = function(){
if(socket) return $q.resolve(socket);
return tryGetData();
}
}]);
其余的代码看起来不错。在angular中,服务是单例的,因此这确实是您想要的。但是,您的服务构建方式存在一些问题;具体来说,您在回调中使用
。此将无法按预期工作,因为。此指的是回调,而不是父服务。此外,您应该考虑切换到<代码>。然后,<代码> >而不是被禁止的<代码>。成功< /代码>。删除不赞成的<代码>。成功< /代码>并切换到<代码>。然后< /代码>约定。您仍然使用<代码>。这是不起作用的主要部分。在angular services和factory中是单例的。如果您是Javascript新手,那么您将需要花一些时间阅读这个的工作原理,因为它是常见的bug源。这很接近,但tryGetData()并没有返回ui路由器的resolve可以处理的承诺。我有一个解决方案,我创建一个$q延迟对象并返回该延迟对象的承诺。我将发布该解决方案,但我想感谢您的帮助。是的,$http
确实会返回一个承诺。但是按照这里编写的方式,tryGetData()
不会返回该承诺,因为已经调用了.then()
。不知道如何用合适的术语来解释它。此外,我还需要一种方法来处理从$http.get
返回的数据,然后再返回promise结果。因此,我需要抓住$http
承诺,并重新播放另一个。至少这是我的观察结果。我可能完全错了……你错了。检查这个:而且值得注意的是,既然承诺是单子,这就是为什么你可以像这样执行链接。太棒了。我不知道我之前尝试这个时是否忘记重新加载代码或其他东西。它现在肯定能工作了,当然也省去了我添加的所有额外内容。我确实学到了很多。谢谢你的帮助!