質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.35%

  • JavaScript

    11267questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    4914questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • Monaca

    721questions

    「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

  • Cordova

    293questions

    Cordovaは様々なデバイスで使うことができるオープンソースなモバイル用開発プラットフォームです。開発者に各デバイスの元のプラットフォームで開発する必要をなくし、HTML・JavaScript・CSSなどの一般的なウェブのテクノロジーを使ってすべてのデバイスで展開することができるモバイルのアプリケーションを生成することを可能にします。

JavaScriptの繰り返し処理(for文)がうまくいきません

解決済

回答 1

投稿 2017/12/06 13:47 ・編集 2017/12/06 13:47

  • 評価
  • クリップ 0
  • VIEW 265

agepan

score 45

現在下記のようなコードで、特定のフォルダの中にあるファイルをfor文を用いて取得・HTML上にフォルダ名を表示しようとしています。

特定のフォルダの名前はfolderListの配列にある「りんご」と「みかん」の2つです。
このコードを動かしてみると画面上には「みかん」「みかん」と、「りんご」が表示されずに「みかん」が2個表示されてしまいます。

繰り返し処理の変数iを調べるため、コード内の2箇所にアラートを付けて(「最初のアラート」と「2つ目のアラート」)確認してみました。すると画面に出た順序と内容は以下のようになりました。

(1)「最初のアラート0」
(2)「最初のアラート1」
(3)「2つ目のアラート1」
(4)「2つ目のアラート1」

この順序と動きを以下のようになるようにしたいのですが、どのようにコードを書き直せば良いでしょうか。よろしくお願いいたします。

(1)「最初のアラート0」
(2)「2つ目のアラート0」
(3)「最初のアラート1」
(4)「2つ目のアラート1」

var folderList = ['りんご', 'みかん'];
localStorage.setItem('folderList', folderList);

for (var i = 0; i < folderList.length; i++){

  alert('最初のアラート' + i);
  sessionStorage.setItem('i', i); // 繰り返しカウントを保存

  var fileName = 'file.txt';
  var folderUrl = cordova.file.documentsDirectory + folderList[i] + '/';
  var folderList = localStorage.getItem('folderList');

  window.resolveLocalFileSystemURL( folderUrl ,
   function getDirectoryEntry( directoryEntry ) {  
      directoryEntry.getFile( fileName, null,
        function readFile( fileEntry ) {
          fileEntry.file(
            function( file ) {
              var reader = new FileReader();
              reader.onloadend = function() {
                var settings = this.result; 
                    settings = JSON.parse(result);

                var persistentUrl = localStorage.getItem('persistentUrl');
                var folderList = localStorage.getItem('folderList');

                var i = sessionStorage.getItem('i');
                    i = Number(i);
                alert('2つ目のアラート' + i);

                $('#div').append(
                  '<p>' + folderList[i] + '</p>'
                );

              };
              reader.readAsText(file);
            },  
            function fail(e) {
              // エラー処理
            }  
          );
        },
        function fail(e) {
          // エラー処理
        }  
      );
    },
    function fail(e) {
      // エラー処理
    }  
  );

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

非同期処理をループの中で素朴にやろうとするとどうしてもそういうことになると思います。

for (i = 0; i < N; i++) {
  var param = ...;
  // 非同期処理起動
  startAsync(param, function () {
    // 非同期処理終了時処理
    $(...).append(...);
  }
}

一般にこうかくとstartAsyncは並行して一斉に始まってしまい、完了した順番に終了時処理が起動されてしまいます。一般にコールバックを用いる前提で非同期処理を順番にやるには、次のようにコールバックをネストさせる方法(所謂コールバック地獄)を取らざるを得ないのですが、いくつの非同期処理があるかわからない現在のforループをこのように書き換えるのは現実的ではないと思います。

startAsync1(param1, function () {
  // 1番目の完了処理
  ...
  // 2番目の開始
  startAsync2(param2, function () {
    // 2番目の完了処理
    ...
    // 3番目の開始
    startAsync3(param3, function () {
      ...
    }
  }
}

そこでfor文を生かし任意の回数の非同期処理を順番に実行するアイデアとしては例えば次のようにする手があると思います。

var tasks = [];
for (i = 0; i < N; i++) {
  // 非同期処理を行う関数を一旦配列へ用意する
  tasks.push(function (i) {
    var param = ...;
    // i番目の非同期処理の開始
    startAsync(param, function (result) {
      // i番目の非同期処理の完了時処理
      $(...).append(...);
      // i+1番目の非同期処理を起動
      var next = tasks.shift()
      if (next) next(i + 1);
    }
  });
}
var first = tasks.shift();
if (first) first(0); // 最初の非同期処理開始
// この時点ではまだどの非同期処理も終わっていないことに注意

上記はループ毎に唯一の非同期処理しか動かしていませんが、実際はいくつかネストした非同期処理をループ毎にやっておられるようなので、もう少し複雑になると思います。

ES2015のasync/awaitや他のフレームワークならもっと違う書き方もできそうですが、タグに記載されたものに限定し比較的平易な方法と思ったのでコールバックを用いた例をコメントしてみました。

投稿 2017/12/06 15:13

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/06 16:06

    ご回答ありがとうございました!
    仕組みについて大変よく勉強になりました。お教え頂いたコードを自分なりにかみ砕きまして、非同期処理が1回完了するごとにそのカウントをsessionStorageに保存し、if文でフォルダ数とそのカウントが同じになるまで自分自身の関数を繰り返し実行させるコードにしてみたところ、理想的な動きをするようになりました。

    ありがとうございました!

    キャンセル

  • 2017/12/06 16:31

    なるほどそういう方法もありますね!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • JavaScript

    11267questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    4914questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • Monaca

    721questions

    「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

  • Cordova

    293questions

    Cordovaは様々なデバイスで使うことができるオープンソースなモバイル用開発プラットフォームです。開発者に各デバイスの元のプラットフォームで開発する必要をなくし、HTML・JavaScript・CSSなどの一般的なウェブのテクノロジーを使ってすべてのデバイスで展開することができるモバイルのアプリケーションを生成することを可能にします。