Javascript 同步访问由异步请求填充的结构
我试图为JS/jQuery中实现的应用程序提供一个状态值字典。这些值必须从服务器(ajax)获取。我希望以异步的方式完成这项工作,以便在初始化期间启动该请求。以后应该同步访问这些值,以使代码易于理解。 目前简化的代码如下所示: 初始化:Javascript 同步访问由异步请求填充的结构,javascript,jquery,asynchronous,Javascript,Jquery,Asynchronous,我试图为JS/jQuery中实现的应用程序提供一个状态值字典。这些值必须从服务器(ajax)获取。我希望以异步的方式完成这项工作,以便在初始化期间启动该请求。以后应该同步访问这些值,以使代码易于理解。 目前简化的代码如下所示: 初始化: $(document).ready(function(){ Status.fetch(); }) 结构: Status:{ Valid:new $.Deferred(), Server:{}, /* ... */ fet
$(document).ready(function(){
Status.fetch();
})
结构:
Status:{
Valid:new $.Deferred(),
Server:{},
/* ... */
fetch:function(){
if (Status.Valid.isResolved()){
// status already present due to a past request
return Status.Valid.promise();
}else{
// fetch status information from server
$.ajax({
type: 'GET',
url: 'status.php'),
cache: true,
dataType: 'json'
}).done(function(response){
$.each(response,function(key,val){
Status.Server[key]=val;
});
Status.Valid.resolve(Status.Server);
}).fail(function(response){
Status.Valid.reject(NaN);
});
return Status.Valid.promise();
}
}, // Status.fetch
getServerAspect:function(aspect){
$.when(
Status.fetch()
).done(function(server){
return server[aspect];
}).fail(function(server){
return NaN;
})
/* whyever: processing always comes here, which I don't understand... */
}, // Status.getServerAspect
} // Status
Status.Server
由ajax调用填充(该调用有效)Status.getServerAspect()
是一个允许同步访问存储在Status.Server
结构(不工作)中的方面的方法示例
其基本思想是在访问结构之前运行结构的异步填充。每个(同步)访问意味着要么立即返回所引用的方面,要么阻塞,直到该值出现。但是无论我在Status.getServerAspect()
中尝试什么样式,该方法都会立即返回,而不会在调用范围中使用任何方面值
显然,我很难理解使用延迟对象的基本概念。我一直使用它们进行同步处理,效果很好。但这意味着您必须在整个应用程序中使用异步样式。对于此特殊功能,我更喜欢同步样式,以便条件表达式保持简单:
if ('somevalue'==Status.getServerAspect('someaspect'))
...do something...
在异步和同步处理之间建立“桥梁”的诀窍是什么 在
$.ajax
请求中,您可以将async
属性设置为true或false,或者将其传递到函数中
$.when(
Status.fetch(true)
示例见下文
Status:{
Valid:new $.Deferred(),
Server:{},
/* ... */
fetch:function(asyncType){ /// boolean passed as param
if (Status.Valid.isResolved()){
// status already present due to a past request
return Status.Valid.promise();
}else{
// fetch status information from server
$.ajax({
type: 'GET',
url: 'status.php'),
cache: true,
dataType: 'json',
async: asyncType /////// will be true or false
}).done(function(response){
$.each(response,function(key,val){
Status.Server[key]=val;
});
Status.Valid.resolve(Status.Server);
}).fail(function(response){
Status.Valid.reject(NaN);
});
让getServerAspect简单地返回承诺,然后使用它
getServerAspect: function(){
return Status.Valid.promise();
}
现在,您可以将其用于:
Status.getServerAspect().done(function(data){
if (data.someaspect == 'somevalue') {
// do something, but don't return!
}
})
异步代码就是这样工作的
你也可以把它抽象成一个函数,但我发现它更难理解
Status.getServerAspect: function(aspect,callback){
Status.Valid.promise().done(function(data){
callback(data[aspect]);
})
}
现在您可以像这样使用它:
Status.getServerAspect('someaspect',function(value) {
if ( 'somevalue' == value ) {
// do something but don't return!
}
});
很难调用异步进程并使其同步,最简单的方法是将函数分成两部分;一个在异步调用之前,一个在异步调用之后 我发现最好的方法是使用promise模式,或者您可以尝试一个中介,并向其传递一系列由流程的每个步骤触发的事件:
据我所知,JavaScript并不像其他语言那样具有暂停或等待功能。我想与大家分享我最终找到的解决方案。这不是一件优雅的事情,但它以积极的方式回答了最初的问题。因此,它提供了一种根据请求组合异步和同步访问的方法 我认为添加这个答案是有意义的,因为所有其他贡献者都声称这根本不可能 所需的只是实现一个阻塞例程,确保仅当异步检索的数据结构可用时才返回请求的值。因此,这里没有什么神奇之处,最后只是一个简单的“等待”策略:
getServerAspect:function(aspect){
/* the state of the asynchronous retrieval attempt */
var resolution=Status.Valid.state();
while ("pending"==resolution) {
setTimeout(function(){resolution=Status.Valid.state();},500);
}
/* asynchronous retrieval has finished */
if ("resolved"==resolution){
/* return vaule should be available */
return server[aspect];
}else{
/* data could not be retrieved, something is borked */
return NaN;
}
}, // Status.getServerAspect
[由于我的现实世界解决方案更为复杂,因此此函数简化并从内存中写入。]
实际上,该函数在等待解决方案时会阻塞gui。这并不优雅,但请注意,在原始版本中,明确要求使用阻塞行为。在正常情况下,在请求服务器方面之前,检索应该早就完成了,因此“正常”没有阻塞。对于这种情况,我更愿意等待半秒钟,因为即使在异步处理中,最终操作也会延迟到检索完成
这种阻塞策略允许我保持代码的其余部分更加简单和易于阅读,因为我不必一直使用匿名函数。相反,我可以在一个简单的条件语句中访问值:
if ("expected"==Status.getServerAspect('someaspect')){
/* do something */
}
这将起作用,因为setTimeout(…)调用(异步时)仅确保Status.Valid.state();电话不是经常打。这仍然是一个繁忙的等待,它不仅会阻塞线程(因此,不应该在WebWorker之外执行),而且还会占用CPU的空闲时间。事实上,与使用这种方法不同,使用同步AJAX请求是更好的解决方案。在为呼叫者阻塞时,等待不会很忙。但是,如果可以,您仍然应该使用纯异步实现 在获得数据之前,您使用什么来“阻止”?据我所知,除了ajax之外,在现代浏览器中这是不可能的sync@KevinB我尝试使用一个由异步获取过程解析的延迟对象。稍后,我尝试通过在
$中计算延迟对象来阻止访问。至少这是个想法…对,但这不是阻塞,它是异步的。您无法从.done()
回调返回数据。您需要设置async参数并将其设置为false,以允许ajax在继续执行其余代码之前完成其请求,或者使ajax同步,或者使代码异步。你不能两者兼得,但我不希望ajax请求是同步的。它应该在初始化期间触发,并等待时间。将其设置为false,这将需要时间,在它完成之前不会执行任何其他操作finished@CR41G14async:false在web workers之外是一种非常糟糕的做法,因为它会影响用户体验。@Kevin B当代码的其余部分依赖于ajax请求时,通常会有更好的方法使用async。当然,这是我通常做的(我写的)。但这使得条件语句复杂且容易出错。我正在寻找一种解决方案,使条件语句与异步语句保持一致。我的想法是将异步内容移动到“包装器”方法中。但是怎么做呢?当然,但是它是