2011-11-26 15 views
6

私は、起動する前に5000msの遅延が必要な非同期機能を持っています。私はこれを達成するためにsetTimeout()を使用しようとしています。この非同期関数は、複数回実行されるループで発生し、非同期関数が毎回異なるデータを渡すため、setInterval()はここでは使用できません。非同期機能のsetTimeout

問題:非同期機能は何が起こった、と私はそれをどのように解決することができます

Javascriptのコード

5件の Doneメッセージがinstantly`遅延(コンソールプリントせずに即座にトリガされ、遅滞なくループします。?
someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     setTimeout(asyncFunction(listing, function(data) { 
      console.log('Done'); 
     }), 5000); 
    } 
}); 
+0

"listings"が実際に配列の場合は、 "for ... in"を反復しないでください。代わりに数値インデックスを使用します。 – Pointy

+0

@Pointyはいそれは単なる配列です、oops :) – Nyxynyx

答えて

9

他の関数で関数をラップする必要があります。現在、関数を呼び出して、戻り値を引数としてsetTimeoutに渡します。以下のコードは、(correc tly)関数をsetTimeoutに渡します。 5秒後、関数が実行されます。

スコープの問題のために、私は2つの機能を追加しなければなりませんでした。 5秒後、ループは既に終了しており、変数listingは、最後の要素listingsに等しくなります。

someFunction(listings, function() { 
    var counter = 0; // Define counter for 5 second-delays between each call 
    for (var i in listings) { 
     var listing = listings[i]; 
     (function(listing){ //Closure function 
      setTimeout(function(){ //setTimeout function 
       // Because of the closure, `listing` is unique 
       asyncFunction(listing, function(a, b) { 
        console.log('Done'); 
       }); 
      }, 5000 * ++counter); //Increase counter for each loop 
     })(listing); 
    } 
}); 
+0

これは引き続きn回のタイムアウトをほぼ同時に引き起こします。 – jAndy

+0

返信いただきありがとうございます!最初の5000msの遅延がありますが、その後のasyncFunctionの呼び出しはただちに発生します!後続の関数呼び出しに遅延があり、各呼び出しが5000ms離れていてもかまいませんか? – Nyxynyx

+0

古典的なループ/スコープの問題( "リスト"変数)もあります – Pointy

-1

これは違いです。重要な点はasyncFunctionですか?あなたはそれを貼り付けることができますか?

var foo=function(){ 
    alert("BAR"); 
    return function(){ 
     alert("I AM!"); 
    }; 
} 
setTimeout(foo(),4000); 
setTimeout(foo,5000); 
+4

最初の "setTimeout()"は不正です。すぐに "foo()"を呼び出し、その* result *を "setTimeout()"に渡します。 2番目の文字列を渡すと、一般的に非推奨とみなされます。 – Pointy

+0

はい、渡す文字列は 'eval'してからグローバルスコープで実行します。非常に悪い考え – Rifat

+0

ありがとう! – island205

1

は、あなたのasyncFunctionが何を知らない、単にあなたがそれを渡された関数を返すことができると思われます。

someFunction(listings, function() { 
    for (var i = 0; i < listings.length; ++i) { 
     setTimeout(asyncFunction(listings[i], function(data) { 
      console.log('Done'); 
     }), 5000 * i); 
    } 
}); 

function asyncFunction(lstng, func) { 
    return func; 
} 

私はあなたがいくつかの追加ロジックをまとめておく必要があると思います。 setTimeoutに返された新しい機能で必要とされるものは何でも

function asyncFunction(lstng, func) { 
    return function() { 
     // do some stuff with the listing 

     // then invoke the func 
     func(); 
    } 
} 

今すぐあなたのasyncFunctionラップ。新しい関数は、渡されたコールバックも呼び出します。


JSFIDDLE DEMO

+0

ありがとう、 'counter'の代わりに' i'を使ってコード行を減らしました。 asyncFunctionは 'data'の中で2つのコールバック値を使用し、それらを別のサーバに送ります。 – Nyxynyx

+0

@Nyxynyx:あなたが何を意味しているかを完全には分かっていませんが、必要なものをコールバック関数に渡すことができます。私の主なポイントは、すでに名前付きの関数を持っていたため、スコープの2つのレベルをインラインで追加する必要はありません。 'asyncFunction'を変更して、' setTimeout'によって呼び出される関数を返すようにするだけです。これはよりクリーンなアプローチです。 – RightSaidFred

4

あなたがPromiseを使用することができますECMAScript6を使用している場合。

だから、約束にsetTimeoutメソッドへの呼び出しをラップ遅延関数を作成:

function delay(ms) { 
    return new Promise(function (resolve) { return setTimeout(resolve, ms); }); 
}; 

そして、あなたがそのようにそれを使用することができます:

someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     delay(5000).then(() => { 
      return asyncFunction(listing); 
     }).then(() => { 
      console.log('Done'); 
     }); 
    } 
}); 

あなたが使用することができますECMAScript 2017を使用している場合aync/await

非同期関数は約束を返します。したがって、遅延関数のコードを変更する必要はありません。