APIメソッド呼び出しでJavaScriptを使用する必要があるプロジェクトに取り組んでいます。私はJavaプログラマーで、これまでにWeb開発を行ったことがないため、問題が発生しています。
このAPIメソッドは非同期であり、whileループ内にあります。空の配列を返す場合、whileループは終了します。それ以外の場合、ループします。コード:
var done = true;
do
{
async_api_call(
"method.name",
{
// Do stuff.
},
function(result)
{
if(result.error())
{
console.error(result.error());
}
else
{
// Sets the boolean to true if the returned array is empty, or false otherwise.
done = (result.data().length === 0) ? true : false;
}
}
);
} while (!done);
これは機能しません。 「完了」の値が更新される前にループが終了します。私は主題についていくつか読んでいますが、API呼び出しは非同期であるため、約束またはコールバックを使用する必要があるようですが、上記のコードにそれらを適用する方法を理解できません。
ヘルプをいただければ幸いです!
Promise API を使用することをお勧めします。問題はPromise.all
呼び出しを使用して解決できます。
let promises = [];
while(something){
promises.Push(new Promise((r, j) => {
YourAsyncCall(() => r());
});
}
//Then this returns a promise that will resolve when ALL are so.
Promise.all(promises).then(() => {
//All operations done
});
構文はes6にあります。これはes5に相当するものです(Promise APIは外部に含まれる場合があります)。
var promises = [];
while(something){
promises.Push(new Promise(function(r, j){
YourAsyncCall(function(){ r(); });
});
}
//Then this returns a promise that will resolve when ALL are so.
Promise.all(promises).then(function(){
//All operations done
});
API呼び出しでpromiseを返して、promise配列に直接プッシュすることもできます。
api_call_methodを編集したくない場合は、いつでもコードを新しいプロミスでラップし、終了時にメソッドresolveを呼び出すことができます。
edit:私はあなたのコードのポイントを見ました、ごめんなさい。 Promise.allでは問題が解決しないことに気付きました。
投稿したもの(whileループと制御値を除く)を関数内に配置し、それを再度呼び出す条件に依存します。
その後、外部コードにこの非同期実行を認識させるために、すべてをプロミス内にラップできます。後でサンプルコードをPCに投稿します。
Promiseを使用してアプリケーションのフローを制御し、whileループの代わりに再帰を使用できます。
function asyncOp(resolve, reject) {
//If you're using NodeJS you can use Es6 syntax:
async_api_call("method.name", {}, (result) => {
if(result.error()) {
console.error(result.error());
reject(result.error()); //You can reject the promise, this is optional.
} else {
//If your operation succeeds, resolve the promise and don't call again.
if (result.data().length === 0) {
asyncOp(resolve); //Try again
} else {
resolve(result); //Resolve the promise, pass the result.
}
}
});
}
new Promise((r, j) => {
asyncOp(r, j);
}).then((result) => {
//This will call if your algorithm succeeds!
});
/*
* Please note that "(...) => {}" equivals to "function(...){}"
*/
Promises
を使用したくない場合は、次のようにコードを再構築できます。
var tasks = [];
var index = 0;
function processNextTask()
{
if(++index == tasks.length)
{
// no more tasks
return;
}
async_api_call(
"method.name",
{
// Do stuff.
},
function(result)
{
if(result.error())
{
console.error(result.error());
}
else
{
// process data
setTimeout(processNextTask);
}
}
);
}
また、再帰ソリューションを試すこともできます。
function asyncCall(cb) {
// Some async operation
}
function responseHandler(result) {
if (result.error()) {
console.error(result.error());
} else if(result.data() && result.data().length) {
asyncCall(responseHandler);
}
}
asyncCall(responseHandler);
ループは同期され、非同期タスクは非同期であるため、ループは機能しません。非同期タスクが応答する前にループが終了します。 Promiseを使用して非同期タスクを管理することをお勧めします。
//first wrapping your API into a promise
var async_api_call_promise = function(methodName, someObject){
return new Promise((resolve, reject) => {
async_api_call(methodName, someObject, function(result){
if(result.error()){
reject( result.error() )
}else{
resolve( result.data() )
}
});
})
}
今、あなたのポーリングコードに:
//a local utility because I don't want to repeat myself
var poll = () => async_api_call_promise("method.name", {/*Do stuff.*/});
//your pulling operation
poll().then(
data => data.length === 0 || poll(), //true || tryAgain
err => {
console.error(err);
return poll();
}
).then((done) => {
//done === true
//here you put the code that has to wait for your "loop" to finish
});
約束する理由非同期操作の状態管理を行うためです。なぜそれを自分で実装するのですか?