「それを止める」のではなく、使用している環境の非同期性に合わせてアプリケーションを設計します。
次のようなことをしようとしていると思います:
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 を使用したことがある場合は、Deferred
s を使用したことになります)。
あなたがサーバー環境にいることを考えると、明らかに 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
) は通常、固定数のDeferred
s を引数として渡すことを想定しています。
$.when(dfd1, dfd2).done(function(result1, result2) { ... });
ただし、可変数のDeferred
s があるため、 sapply
の配列を使用して、ハンドラーで暗黙的なオブジェクトを介して各結果にアクセスする必要があります。Deferred
when
done
arguments
Array.forEach(...)
遅いです。ほとんどの場合、通常のfor
ループを使用することをお勧めします。