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

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

ただいまの
回答率

90.47%

  • JavaScript

    17009questions

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

  • ループ

    53questions

    ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

javascriptのループ処理の順番がめちゃくちゃ

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 3,442

ckaposndbbba

score 199

こんにちは。
javascriptであるものを作っていて、その中にループ処理があるのですが、ループする順番がめちゃくちゃなんです。
forでもwhileでもダメです。25回ループしたいです。
コードは下記。
<ul class="result"></ul>
// while
var i = 1;
while (i < 26){
    $('.result').append('<li>' + i + '</li>');
    i++;
}

//for
for (var i = 1; i < 26; i++) {
    $('.result').append('<li>' + i + '</li>');
}

//どっちもダメ
結果がこうなります。
1
2
3
4
5
6
7
8
10
9
11
12
16
15
14
17
13
18
19
24
22
21
23
20
25
ところどころ順番がメチャクチャになっています。
あと、これ、全部こうなるのではなく、リロードしたら毎回順番が変わります。
そうじゃなくて、「1・2・3・4・5・6・7・・」と、順番通りに動かしたいです。
どうすればいいのでしょうか?
仕様なのでしょうか?解決策やサンプルコードなど提示していただければうれしいです。
よろしくお願いします。


**補足**
めちゃくちゃなコードですが、javascriptの全体の主なコードを貼り付けます。
確認していただけると幸いです。
ちなみに、データベースに接続するPHPと通信して、クイズアプリのようなものを作っています。
console.logや$(function(){など、要らない部分は削除しているので、必要な部分だけとなります。

function mark_question (id, answer, while_i) {
  var URI = 'api.php';
  var dataURI = 'id=' + id + '&answer=' + answer;
  if (answer === undefined) {
    answer = '5';
  }
  $.ajax({
    type: 'GET',
    url: URI,
    dataType: 'json',
    data: dataURI,
    success: function(json){
      console.log('success');
      if(json[detail] == 'true') {
        $('#result_detail:last-child').append('<li>' + while_i + '</li>');
      } else {
        $('#result_detail:last-child').append('<li>' + while_i + '</li>');
      }
    },
    error:function(json){
      console.log('error');
    }
  });
}
//----------------
for (var i = 1; i < 26; i++) {
  var id = $('.c-' + i).attr('data-id');
  var answer = $('.c-' + i).attr('data-answer');
  mark_question(id, answer, i);
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+2

こんにちは。

検証のため、以下の2つのHTMLを作成しました。

(1) http://www.gattolibero.sakura.ne.jp/teratail/q13514-for.html

(2) http://www.gattolibero.sakura.ne.jp/teratail/q13514-while.html

上記を表示させると分かるとおり、問題のズレは生じていないです。

なので、問題解決のために、ループの中のAJAXも含む、HTMLと
javascriptのコード全体を追記して頂ければと思います。


追記1

AJAXを行っているコードをざっと読みました。

forループの中で、たとえば
 mark_question(id, answer, 1);
 mark_question(id, answer, 2);
の2つが、この順で呼ばれますが、それぞれの中で行っているAJAX通信での
レスポンスが、この順で返ってくるとは限りません。
したがって、
 mark_question(id, answer, 2);
でのAJAXのレスポンスが先に返ってきて処理されたら、作られる
リストアイテムは
 <li>2</li>
 <li>1</li>
の順になります。


追記2 

ちょっと応急的な手法になるかと思いますが、
こんな方法を考えてみました。

・APIを呼び出す直前に、内容が空の25個の<li>を作成する。

・その後、ループでAPIを呼び、呼び出し回数に応じた位置の<li>の内容を書き換える。

以下サンプルコードになります。

q13514-improved.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>teratail/q13514-improved</title>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
function call_api(n) {
    $.ajax({
        type: 'GET',
        url: 'api.php',
        dataType: 'json',
        success: function(json){
            console.log("ok:" + n );
            $('.result li:nth-child(' + n + ')').text(n).css({display: 'block'});
        }
    });
}

function make_items()
{
    // まず、内容が空のリストアイテムを25個作成
    for (var i = 1; i < 26; i ++) {
        $('.result').append($('<li>').css({display: 'none'}));
    }
    
    // 25 回 AJAX を行い、回数に応じた位置の li の内容を書き換える。
    for (var i = 1; i < 26; i ++) {
        call_api(i);
    }
}
</script>
</head>
<body>
    <ul class="result"></ul>
    <hr />
    <a href="" onclick="make_items(); return(false);">click me !</a>
</body>
</html>

api.php はとりあえず以下のように、空のJSONを返すだけのものです。

api.php
<?php
header("Content-Type: application/json; charset=utf-8");

echo '{}'; 

上記のq13514-improved.htmlとapi.phpを作成して以下に上げました。

 http://www.gattolibero.sakura.ne.jp/teratail/q13514-improved.html

http://www.gattolibero.sakura.ne.jp/teratail/api.php

click me ! をクリックすると、AJAXのレスポンスの順番が、
ループの順にならなくても、リストの表示としては順番に
なります。


投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/07/27 19:56

    わざわざありがとうございます!
    では、補足としてソースを記入します。よろしくお願いします。

    キャンセル

  • 2015/07/27 21:21

    ちょっと対症療法的というか、とりあえずの応急措置っぽい方法ですが、対策を考えてみました。追記2 をご覧ください。何か参考になれば幸いです。

    キャンセル

  • 2015/07/28 21:04

    ありがとうございます!提示された方法を真似てやってみたら、成功しました!
    ありがとうございましたm(_ _)m

    キャンセル

  • 2015/07/29 03:45

    どういたしまして。解決されたようで、よかったです!

    キャンセル

+1

もしかして本当は次のように中で ajax で処理してコールバックの中でリストを追加しているのでしょうか?

for (var i = 1; i < 26; i++) {
    (function(){
        var j = i;
        $.ajax('?', {}).then(function(){
            $('.result').append('<li>' + j + '</li>');
        });
    }())
}

この場合、ajax が直列に実行されるようにするか、

var defer = $.Deferred().resolve();

for (var i = 1; i < 26; i++) {
    (function(){
        var j = i;
        defer = defer.then(function(){
            return $.ajax('?', {}).then(function(){
                $('.result').append('<li>' + j + '</li>');
            });
        })
    }())
}

非同期処理の待ち合わせをする必要があります。

var list = [];

for (var i = 1; i < 26; i++) {
    (function(){
        var j = i;
        var x = $.ajax('?', {}).then(function(){
            return j;
        });
        list.push(x);
    }())
}

$.when.apply(null, list).then(function(){
    $.each(arguments, function(i, j){
        $('.result').append('<li>' + j + '</li>');
    });
})

ひとまず、ajax も絡めた実際のコードを質問に追記すると良いかと思います。


$.ajax の引数の success は使わずに $.ajax の戻り値の then で処理するようにします。

then に渡すコールバック関数の引数は・・ success に渡すコールバック関数の引数とは違った気がするのですが、パッと思い出せないので調べてください。

mark_question 関数は then の戻り値を返します。

これらは関数の呼び出し元で Promise を利用するためです。

関数の呼び出し側のコードで Promise を直列につなげます。

かなり簡略化しましたが、下記のような感じです。

function mark_question (while_i) {
    return $.ajax({
        type: 'get',
        url: '?'
    })
    .then(function(){
        $('.result').append('<li>' + while_i + '</li>');
    })
}

var defer = $.Deferred().resolve();

for (var i = 1; i < 26; i++) {
    (function(){
        var j = i;
        defer = defer.then(function(){
            return mark_question(j)
        });
    }())
}

もし、これが何をやっているのかわからないなら、jQuery と Deferred(Promise) について学ぶ必要があります。

なお、これは↑であげた2番目のコード例です(ajax が直列に実行されるようにする)。
3番目の「非同期処理の待ち合わせ」でも、頑張ればできます。


投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/07/27 19:56

    ありがとうございます!
    では、補足としてソースを記入します。よろしくお願いします。

    キャンセル

0

JQuery は基本非同期なので、タグ追加程度ならJSでやった方が良いと思いますよ。

JQuery でやるならば下記のようにタグを作ってから追加すればよいかと。
// while
var i = 1;
var tags = '';

while ( i < 26 )
{
    tags += '<li>' + i + '</li>';
    i++;
}

$('.result').append(tags);

tags = '';
//for
for( var i = 1; i < 26; i++ )
{
    tags += '<li>' + i + '</li>';
}
$('.result').append(tags );

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/07/27 19:29

    ありがとうございます。
    実は、ループ処理の中の、要らない部分は削除して書いています。
    本当は、ループ処理の中に、Ajax通信の処理が含まれているのです(>_<)
    そのような場合?はどうすればいいでしょうか?

    キャンセル

0

for (var i = 1; i < 26; i++) {
  $('.result:last-child').append('<li>' + i + '</li>');
}
これでどうでしょうか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/07/27 19:29

    ありがとうございます!
    早速、提示された方法を試してみたのですが、やはりうまく行きませんでした・・><

    キャンセル

  • 2015/07/27 19:38 編集

    単純にループだけなら上記ソースで間違いなく動くと思うのですが、NIA様へのコメントを拝見するとAjax通信が割り込んでいるそうで。
    非同期通信ですと応答順に表示されるはずですから、それでずれてるんだと思います。
    同期通信にすれば解決するかと思いますが、いかがでしょうか。

    キャンセル

  • 2015/07/27 19:46

    そうなんですか。
    では、(めちゃくちゃなコードですが、すみません)コードを一部貼り付けます><
    長くなるかもしれませんがどうぞ。


    function mark_question (id, answer, while_i) {
    var URI = 'api.php';
    var dataURI = 'id=' + id + '&answer=' + answer;
    if (answer === undefined) {
    answer = '5';
    }
    $.ajax({
    type: 'GET',
    url: URI,
    dataType: 'json',
    data: dataURI,
    success: function(json){
    console.log('success');
    if(json[detail] == 'true') {
    $('#result_detail:last-child').append('<li>' + while_i + '</li>');
    } else {
    $('#result_detail:last-child').append('<li>' + while_i + '</li>');
    }
    },
    error:function(json){
    console.log('error');
    }
    });
    }
    ----------------
    for (var i = 1; i < 26; i++) {
    var id = $('.c-' + i).attr('data-id');
    var answer = $('.c-' + i).attr('data-answer');
    mark_question(id, answer, i);
    }

    キャンセル

  • 2015/07/27 20:00

    ajaxの引数に、

    async:false

    を追加すればひとまず目的は達成できるかと思いますが、処理待ちで画面がフリーズするかもしれないのでお勧めはできません(汗
    他の方のご回答を参考にして、一番いい方法を使ってください!

    キャンセル

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

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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

  • JavaScript

    17009questions

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

  • ループ

    53questions

    ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します