0

したがって、私のサーバー コードでは、success 関数の外では変数の招集が定義されていません。

function getInvites(id){
    var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
    var invites;
    InvitesTable.read({ success: function(resultss) { 
                           invites = resultss;
                           console.log(invites); //works here
                           }});
    console.log(invites); //undefined here
}

同様の質問から、非同期であることが原因であることがわかります。したがって、成功関数呼び出しはconsole.log(invites); //undefined here呼び出しの後に実行されます。

私の質問は、Windows Azure でそれを停止するにはどうすればよいですか?

追加されたコード

function read(query, user, request) {

        request.execute({
            success: function(results) {
                results.forEach(function(r) {

                    getInvites(r.id, function(invites) {
                        r.invites = invites;
                    });
                });
                request.respond();
            }
        });

}

function getInvites(id, cb){
    var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
    InvitesTable.read({ success: function(results) {
                           if (cb) cb(results);
                           }});
}
4

2 に答える 2

5

「それを止める」のではなく、使用している環境の非同期性に合わせてアプリケーションを設計します。

次のようなことをしようとしていると思います:

function getInvites(id){
    var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
    var invites;
    InvitesTable.read({ success: function(resultss) { 
                           invites = resultss;
                           }});
    return invites;
}

// later...

var invites = getInvites(someId);
//do something with `invites`

invites非同期呼び出しが完了する前に値を返すため、これは明らかに機能しません。

代わりに、非同期スタイルでアプリを作成します。

function getInvites(id, cb){
    var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
    InvitesTable.read({ success: function(resultss) { 
                           if (cb) cb(resultss);
                           }});
}

// later...

getInvites(someId, function(invites) {
    //do something with `invites`
});

これは単純化のためにエラー処理コードを除外しているので、それも追加する必要があります。


コード全体を見ると、多くの並列非同期操作を管理するという単純な問題があるように見えます。何が起こるか考えてみてください: ループが実行され、 n 個のオブジェクトの配列を反復処理します。それぞれに対して を呼び出します。getInvitesこれは、データベース リクエストを開始して戻ります。

これは、ループが非常に速く実行されることを意味しますが、 を呼び出す前に待機する必要がある未処理のデータベース リクエストがn 個request.respond()あります。

非常に基本的な解決策は、コールバックが呼び出された回数をカウントし、その回数がngetInvitesに達したときに最終的にリクエストを完了するようなことです。

ただし、非同期リクエストを行うたびにこの簿記を手動で管理するのは時間がかかり、ミスが発生しやすくなります。これは、フロー制御ライブラリが非常に役立つ状況です。この例では jQuery を使用Deferredしますが、これは既におなじみかもしれません (以前に実際に使用したことがなくても、jQuery の XHR API を使用したことがある場合は、Deferreds を使用したことになります)。

あなたがサーバー環境にいることを考えると、明らかに jQuery はありません。ただし、必要なコードだけを抽出しDeferredた人がいます

Deferred保留中のリクエストごとにを取得したら、保留中のすべてwhenの が完了した後にのみ呼び出されるコールバックを登録するために使用できます。Deferred

function read(query, user, request) {

        request.execute({
            success: function(results) {
                var dfds = [];
                for (var i = 0; i < results.length; i++) {
                    dfds.push(getInvites(results[i].id)); // Makes an array of Deferreds representing
                                                          // each of our pending requests.
                }


                Deferred.when.apply(Deferred, dfds) // see details below
                    .done(function() {
                        for (var i = 0; i < results.length; i++) {
                            results[i].invites = arguments[i]; // Copy each set of invites to each result
                        }
                        request.respond(); // We're done!
                    })
                    .fail(function() {
                        // Handle errors here
                    });
            }
        });

}

function getInvites(id){
    var dfd = new Deferred(); // Create a new Deferred, which automatically starts in the 'pending' state
    var InvitesTable = tables.getTable("Invites").where({"PlanID": id}).select("UserID","Attending");
    InvitesTable.read({ success: function(results) {
                           dfd.resolve(results); // When we get data back, we 'resolve' the Deferred --
                                                 // in other words, say its operation is done,
                                                 // and pass along the operation's results.
                           },
                        error: function(err) { // TODO: Not sure if this is how the API you're using handles errors
                            dfd.reject(err); // Marks the Deferred as failed.
                        }});

    return dfd.promise(); // We (synchronously) return the Promise.  The caller can attach event handlers
                          // to the Promise, which are invoked when we eventually resolve or reject the Deferred.
}

ノート:

  • jQuery.when(または、このサーバー側の場合、Deferred.when) は通常、固定数のDeferreds を引数として渡すことを想定しています。

    $.when(dfd1, dfd2).done(function(result1, result2) { ... });
    

    ただし、可変数のDeferreds があるため、 sapplyの配列を使用して、ハンドラーで暗黙的なオブジェクトを介して各結果にアクセスする必要があります。Deferredwhendonearguments

  • Array.forEach(...) 遅いです。ほとんどの場合、通常のforループを使用することをお勧めします。

于 2013-01-14T21:42:55.400 に答える
0

同期 DB アクセスの同じ必要性に出くわしたので、query-synchronizerという小さなモジュールを作成しました。アイデアは、クエリが開始および終了した回数をカウントすることでした。すべての開始カウントが終了カウントと等しい場合、コードの他の部分が実行されます。コードは次のようになります。

var synchronizer = require('query-synchronizer');

function read(query, user, request) {
    request.execute({
        success: function(results) {
            results.forEach(function(r) {
                var InvitesTable = tables.getTable("Invites").where({"PlanID": r.id}).select("UserID","Attending");
                synchronizer.read(InvitesTable, function(results){
                    r.invites = invites;
                });

            });
            synchronizer.done(function(){
                request.respond();
            });
        }
    });

}
于 2013-10-28T16:35:39.683 に答える