[解決済み] javascriptのforループ内の非同期処理 [重複]について
質問
以下のフォームのイベントループを実行しています。
var i;
var j = 10;
for (i = 0; i < j; i++) {
asynchronousProcess(callbackFunction() {
alert(i);
});
}
私は、0から10までの数字を示す一連のアラートを表示しようとしています。問題は、コールバック関数がトリガーされた時点で、ループがすでに数回繰り返されているため、より高い値である
i
. これを修正する方法について、何かお勧めがあれば教えてください。
解決方法は?
その
for
ループは、すべての非同期処理が開始される間、完了するまで直ちに実行されます。 それらが将来的に完了し、コールバックを呼び出すと、ループインデックス変数
i
は、すべてのコールバックに対して最後の値になります。
これは
for
ループは非同期処理の完了を待たずに次の反復処理に進み、非同期コールバックは将来のある時点で呼び出されるからです。 したがって、ループは反復を完了し、その後、非同期操作が終了したときにコールバックが呼び出されます。 そのため、ループのインデックスは、すべてのコールバックに対して最終的な値で、quot;done"されています。
これを回避するためには、各コールバックごとにループインデックスを一意に保存する必要があります。 Javascriptでは、関数のクロージャにそれを取り込む方法があります。 これは、この目的のためにインライン関数クロージャを作成する方法(以下の最初の例)と、インデックスを渡す外部関数を作成し、インデックスを一意に保持させる方法(以下の2番目の例)のいずれかによって行われます。
2016年現在、JavascriptのES6実装を完全にアップ・トゥ・スペックにしている場合、さらに
let
を定義するために
for
ループ変数が定義され、その変数は
for
ループを使用します(下記3番目の実装)。 ただし、これはES6の実装では後発の機能なので、実行環境がそのオプションをサポートしているかどうか確認する必要があることに注意してください。
.forEach()は独自の関数クロージャを作成するので、反復処理に使用します。
someArray.forEach(function(item, i) {
asynchronousProcess(function(item) {
console.log(i);
});
});
IIFEを使用して独自の関数クロージャを作成する
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asynchronousProcess(function() {
console.log(cntr);
});
})(i);
}
外部関数を作成または変更し、その変数を渡す
を修正することができれば
asynchronousProcess()
関数に値を渡して
asynchronousProcess()
関数で、このようにcntrをコールバックに返します。
var j = 10;
for (var i = 0; i < j; i++) {
asynchronousProcess(i, function(cntr) {
console.log(cntr);
});
}
ES6を使用
let
ES6を完全にサポートするJavascriptの実行環境がある場合は
let
の中で
for
のようなループになります。
const j = 10;
for (let i = 0; i < j; i++) {
asynchronousProcess(function() {
console.log(i);
});
}
let
で宣言された
for
このようなループ宣言を行うと、一意な値である
i
をループの各呼び出しに使用します (これは、あなたが望むことです)。
プロミスとasync/awaitを使ったシリアライジング
非同期関数がプロミスを返し、非同期処理を並列ではなく次々に実行するためにシリアライズしたい場合、そして、あなたが
async
と
await
であれば、選択肢は広がります。
async function someFunction() {
const j = 10;
for (let i = 0; i < j; i++) {
// wait for the promise to resolve before advancing the for loop
await asynchronousProcess();
console.log(i);
}
}
これは
asynchronousProcess()
は一度に飛行中であり
for
のループは、それぞれが終了するまで進んでもくれません。 これは、非同期処理を並列に実行するこれまでの方式とは異なるので、どのような設計にするかはあなた次第です。 注
await
はプロミスで動作するため、関数は非同期処理の完了時に解決/拒否されるプロミスを返さなければなりません。 また
await
を含む関数が宣言されている必要があります。
async
.
非同期処理を並列に実行し
Promise.all()
順番に結果を収集するために
function someFunction() {
let promises = [];
for (let i = 0; i < 10; i++) {
promises.push(asynchonousProcessThatReturnsPromise());
}
return Promise.all(promises);
}
someFunction().then(results => {
// array of results in order here
console.log(results);
}).catch(err => {
console.log(err);
});
関連
-
Vue Element-uiは、アイコンを追加するためのツリーコントロールノードを詳細に実装しています。
-
元のイベントが実行されなかった後に要素を追加するためのjQueryソリューション
-
[解決済み】Uncaught SyntaxError: JSONの位置0に予期しないトークンuがあります。
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptのオブジェクトが空であることをテストするにはどうすればよいですか?
-
[解決済み] JavaScriptのオブジェクトをループスルーまたは列挙するにはどうすればよいですか?
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vueのクラススタイルの使い方の詳細
-
vueのプロジェクトでモックを使用する方法を知っていますか?
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み】JavaScript TypeError: null のプロパティ 'style' を読み取ることができない
-
[解決済み】React-Redux: アクションはプレーンオブジェクトでなければならない。非同期アクションにはカスタムミドルウェアを使用する
-
[解決済み】エラー。Ionic使用中にモジュール '../lib/utils/unsupported.js' が見つかりませんでした。
-
[解決済み】「.addEventListener is not a function」なぜこのエラーが発生するのか?
-
フロントエンド非同期(アシンク)ソリューション(全ソリューション)
-
フロントエンド null のプロパティ 'disabled' を読み取れない 問題が解決された
-
[解決済み] ループ内のJavaScriptクロージャ - シンプルな実用例