-2

我正在尝试为在 JS/jQuery 中实现的应用程序提供状态值字典。这些值必须从服务器(ajax)中获取。我想以异步方式执行此操作,以便可以在初始化期间启动该请求。对值的实际访问应该稍后同步完成,以使代码易于理解。(非常)简化的代码目前如下所示:

初始化:

$(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...

在异步和同步处理之间建立“桥梁”的技巧是什么?

4

5 回答 5

1

这将起作用,因为 setTimeout(...) 调用(异步时)仅确保 Status.Valid.state(); 通话并不经常进行。它仍然是一个繁忙的等待,它不仅会阻塞线程(因此,不应该在 WebWorker 之外完成)而且还会从你的 CPU 中窃取空闲时间。实际上,与其使用这种方法,不如使用同步 AJAX 请求是更好的解决方案。在为呼叫者阻塞时,不会是忙等待。但是,如果可以,您仍然应该使用纯异步实现。

于 2013-04-27T13:50:54.993 回答
0

让 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!
    }
});
于 2013-02-12T16:02:23.067 回答
0

很难调用异步进程并尝试使其同步,最简单的方法是将函数分成两部分;一个在异步调用之前和一个之后。

我发现最好的方法是使用 Promise 模式,或者您可以尝试使用调解器并将一系列事件传递给它,以由您的流程的每一步触发:

用于不同进程使用的多个 xmlhttprequest 的良好模式

据我所知,JavaScript 并没有像其他语言那样真正具有暂停或等待功能。

于 2013-02-12T16:06:53.893 回答
-1

$.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);
        });
于 2013-02-12T15:53:12.157 回答
-2

我想分享我最终找到的解决方案。这不是一件优雅的事情,但它以积极的方式回答了最初的问题。因此,它提供了一种根据请求组合异步和同步访问的方法。

我认为添加这个答案是有意义的,因为所有其他贡献者都声称这根本不可能。

所需要的只是实现一个阻塞例程,以确保仅在异步检索的数据结构可用时才返回请求的值。所以这里没有魔法,最后只是一个简单的“等待”策略:

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 */
}
于 2013-02-17T11:38:00.337 回答