-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.Serverajax呼び出しによって満たされます(これは機能します)。は、構造Status.getServerAspect()内に格納されたアスペクトへの同期アクセスを許可するメソッドの例です(これは機能しませ)。Status.Server

基本的な考え方は、構造体がアクセスされる前に、構造体の非同期充填が実行されるというものです。すべての(同期)アクセスは、参照されたアスペクトをすぐに返すか、その値が存在するまでブロックすることを意味します。しかし、 内でどのようなスタイルを試してStatus.getServerAspect()も、メソッドは呼び出しスコープで使用できるアスペクト値なしですぐに戻ります。

遅延オブジェクトを操作する基本概念を理解するのに明らかに問題があります。私はそれらを常に同期処理に使用していますが、魅力のように機能します。ただし、これは、アプリケーション全体で非同期スタイルを使用する必要があることを意味します。この特別な機能では、条件式をシンプルに保つために、同期スタイルを好みます。

if ('somevalue'==Status.getServerAspect('someaspect'))
    ...do something...

非同期処理と同期処理の間に「ブリッジ」を構築するためのトリックは何ですか?

4

5 に答える 5

0

getServerAspect が単に promise を返すようにしてから、それを使用します。

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

非同期プロセスを呼び出して同期化しようとするのは困難です。最も簡単な方法は、関数を 2 つの部分に分割することです。1 つは非同期呼び出しの前、もう 1 つは後です。

私が見つけた最良の方法は、promise パターンを使用することです。または、メディエーターを試して一連のイベントを渡し、プロセスのすべてのステップでトリガーされるようにすることもできます。

異なるプロセスで使用される複数の xmlhttprequests に使用するのに適したパターン

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 をブロックします。これはエレガントではありませんが、オリジナルではブロック動作が明示的に要求されていることに注意してください。通常の状況では、サーバー アスペクトが要求される前に取得が完了しているはずなので、「通常」はブロックされません。これが当てはまらない状況では、0.5 秒待つことを好みます。これは、非同期処理であっても、取得が完了するまで最終アクションが遅延されるためです。

このブロッキング戦略により、匿名関数を常に使用する必要がないため、コードの残りの部分をよりシンプルで読みやすく保つことができます。代わりに、単純な条件ステートメントで値にアクセスできます。

if ("expected"==Status.getServerAspect('someaspect')){
    /* do something */
}
于 2013-02-17T11:38:00.337 に答える