0

ネストされたeachループがありますが、2 番目のループの Ajax リクエストが、最初のループで宣言した変数に追加されていないようです。

これは私が使用しているものの例です(「個人」情報は除外されています):

var pages = [["Page Title 1", ["Page URL 1", "Page URL 2", "Page URL 3"]], ["Page Title 2", ["Page URL 1", "Page URL 2", "Page URL 3"]], ["Page Title 3", ["Page URL 1", "Page URL 2", "Page URL 3"]]];

function loadFeeds() {
$.each(pages, function(index, page) {
    $(".pages").append("<a class=\"pagename\" href=\"#" + page[0] + "\">" + page[0] + "</a>");
    html = "<div class=\"page\" id=\"" + page[0] + "\">";
    $.each(page[1], function(index, feedUrl) {

    $.ajax({
    type: "GET",
    url: feedUrl,
    processData : true,
    data: {
        tagmode: "any"
        },
    jsonp: "jsonp",
    dataType: "jsonp",
    success: function(data) {
        html += "Some header HTML";

        $.each(data.responseData.feed.entries, function(i,entry) {
            if (entry.image_urls.length === 0) {
                html += "HTML from the data";
            }
            else {
                html += "More HTML";
            }

            if ( i == 34 ) return false;
        });
        html += "Closing tags from the header";
        afterAjax();
        // console.log(html); returns correct information here
    },
            error: function(x,y,z) {
                alert(x.responseText);
            }
        });
    // console.log(html); returns everything declared to html OUTSIDE of the ajax request
    });
        $("body").append(html + "</div>");
    // Also tried: $("body").ajaxStop(function(){ $(this).append(html + "</div>"); }); because Ajax is asynchronous
});
}​

何が起こっているかについてのアイデアはありますか?

編集:

完全な非動作デモ、WIP ページ機能: http://jsfiddle.net/SO_AMK/u42uy/

完全に動作するデモ、ページ機能なし:

フルスクリーン: http://jsfiddle.net/SO_AMK/LXkaN/embedded/result/
通常: http://jsfiddle.net/SO_AMK/LXkaN/

これらには画像がなく、完全なアプリではないことに注意してください。

4

4 に答える 4

2

問題

競合状態のように見えます。AJAX は非同期でsuccess実行されるため、AJAX 応答が正常に受信された後、ハンドラーは将来のある時点で実行されることに注意してください。AJAX リクエストがディスパッチされている間、残りのスクリプトが実行されます。具体的に言えば:

$("body").append(html + "</div>");

成功ハンドラーが起動される前に実行されています。つまり、html変数がまだまったく更新されていません。

解決策 1

動く

$("body").append(html + "</div>");

successハンドラー内。

    html += "Closing tags from the header";
    afterAjax();
    // console.log(html); returns correct information here
    $("body").append(html + "</div>");
},

解決策 2 ($.ajaxStop)

$.ajax()呼び出しを行う前に、必ずハンドラーを登録してください。これにより、ハンドラーを に登録するコードの前に、AJAX 要求が起動して終了することがなくなります.ajaxStop

function loadFeeds() {
    html = "";
    $.ajaxStop(function(){$(document.body).append(html + "</div>);

    $.each(pages, function(index, page) {
        $(".pages").append("<a class=\"pagename\" href=\"#" + page[0] + "\">" + page[0] + "</a>");
        html = "<div class=\"page\" id=\"" + page[0] + "\">";
    ...
}

解決策 3 (jsLint+Deffereds から)

この例は、完全に機能する jsLint リンクから取得したものです。このコードは$.ajax、ループ内で作成されているすべてのリクエストを取得し、それらを配列に格納して、後で$.when().done()呼び出しに適用します。$.when()は適用された各リクエストを検査し$.ajax、完了したら、 で指定されたハンドラを呼び出します$.done()。各$.ajax要求は、その応答をhtml = []の開始時に定義された配列に格納し$.ready()ます。遅延チェック ( $.when()) がすべての$.ajax要求が完了したことを確認したら、配列 ( array.join('')) を結合して 1 つの大きな HTML ブロックを作成し、ドキュメントに追加します。次に、関数を呼び出しますafterAjax()

$(document).ready(function () {
    var html = [];
    var feeds = ["http://pulsesubscriber.appspot.com/items?feed=http://feeds.gawker.com/lifehacker/vip&jsonp=?",
                 "http://pulsesubscriber.appspot.com/items?feed=http://allthingsd.com/feed&jsonp=?",
                 "http://pulsesubscriber.appspot.com/items?feed=http://feeds.cnet.com/latestnews/pulse&jsonp=?"];
    loadFeeds(feeds);

    function loadFeeds(feeds) {
        var requests = [];

        $.each(feeds, function(index, feedUrl) {
            requests.push($.ajax({
                type: "GET",
                url: feedUrl,
                processData : true,
                data: {
                    tagmode: "any"
                    },
                jsonp: "jsonp",
                dataType: "jsonp",
                success: function(data) {
                    var feedElements = "<header class=\"feed-title\"><div class=\"feed-title-content\"><span class=\"feed-title-text\">" +
                        data.responseData.feed.title +
                        "</span></div></header><section class=\"row\"><div class=\"scroll-left\"></div><div class=\"row-scroll\">";

                    $.each(data.responseData.feed.entries, function(index,entry) {
                        var feedElements = '';
                        if (entry.image_urls.length === 0) {
                            feedElements += "<div class=\"tile no-img\"><title class=\"tile-title no-img\">" +
                                entry.title +
                                "</title><hr class=\"no-img hr\" /><span class=\"no-img excerpt\">" +
                                entry.contentSnippet +
                                "</span><div class=\"tile-modal\"><div class=\"article-wrapper\">\r\n<div class=\"article-header\">\r\n<a class=\"article-title-link\" target=\"_blank\" href=\"" +
                                entry.link +
                                "\">\r\n<h1 class=\"article-title\">" +
                                entry.title +
                                "</h1>\r\n</a>\r\n<h2 class=\"article-byline\">By " +
                                entry.author +
                                ": " +
                                data.responseData.feed.title +
                                "</h2>\r\n</div>\r\n<hr class=\"article-hr\"/>\r\n<div class=\"article-content\">" +
                                entry.content +
                                "\r\n<a class=\"read-more\" target=\"_blank\" href=\"" +
                                entry.link +
                                "\">Read More...</a>\r\n</div>\r\n</div></div></div>\r\n";
                        }
                        else {
                                feedElements += "<div class=\"tile\"><img class=\"tile-image\" src=\"" +
                                entry.image_urls[0] +
                                "\" /><title class=\"tile-title\">" +
                                entry.title +
                                "</title><div class=\"tile-modal\"><div class=\"article-wrapper\">\r\n<div class=\"article-header\">\r\n<a class=\"article-title-link\" target=\"_blank\" href=\"" +
                                entry.link +
                                "\">\r\n<h1 class=\"article-title\">" +
                                entry.title +
                                "</h1>\r\n</a>\r\n<h2 class=\"article-byline\">By " +
                                entry.author +
                                ": " +
                                data.responseData.feed.title +
                                "</h2>\r\n</div>\r\n<hr class=\"article-hr\"/>\r\n<div class=\"article-content\">" +
                                entry.content +
                                "\r\n<a class=\"read-more\" target=\"_blank\" href=\"" +
                                entry.link +
                                "\">Read More...</a>\r\n</div>\r\n</div></div></div>\r\n";
                        }
                        html.push(feedElements);
                        console.log('updated elements');
                        if(index == 34 ){
                            return false;
                        }
                    });
                },
                error: function(x,y,z) {
                    console.log(x.responseText);
                }
            }));
        });

        $.when.apply(this,requests).done(function(){
            console.log('when!');
            console.log(html);
            $(document.body).append($(html.join('')));
            afterAjax();
        });

    }



    $("#refresh-all").click(function(){
        $("body > header, body > section").remove();
        $("body").removeClass("active");
        loadFeeds();
    });

    function afterAjax() {
            $(".page:first").addClass("active");
            $(".tile").click(function(){
            if ($(".tile-modal.tile-modal-active").length) {
                $(".tile-modal.tile-modal-active").removeClass("tile-modal-active");
                $(this).children(".tile-modal").addClass("tile-modal-active");
            }
            else {
                $(this).children(".tile-modal").addClass("tile-modal-active");
                $("body").addClass("active");
            }
        });


        $(".scroll-left").hover(function(){
            $(this).parent().animate({scrollLeft: 0}, 7000);
        }, function() {
            $(this).parent().stop();
        });

        $(".scroll-right").hover(function(){
            $(this).parent().animate({scrollLeft: $(this).siblings(".row-scroll").width()}, 7000);
        }, function() {
            $(this).parent().stop();
        });
    }
});

一連のリクエストを実行し、それらがすべて実行されたら別のアクションを実行する場合は、Futures & Promises パターンまたは defereds を利用できます。jQuery では、これは.promise()(Futures/Promises) または.when()(Deffered) を介して行われます。

グローバル変数に関する注意

var html = ...また、使用しないと変数がグローバルになることにも注意してください。これは一般的に眉をひそめています。$("body").append(html+"</div>")成功ハンドラー内を移動して、htmlとしても宣言するのが最善var htmlです。

于 2012-07-16T01:24:14.863 に答える
1

ajax呼び出しが同期的でない限り(そして、それらが同期している兆候は見られません)、各ループは終了し、ajax呼び出しの成功関数が実行される前に戻ります。この方法でコードを構成することはできません。つまり$("body").append(html + "</div>");、ajax 呼び出しが変数に何かを追加する機会を得る前に実行されますhtml

ajax レスポンス コールバックは、ループが完了した後に独自のタイミングで実行される独立したコードとして考え.each()、その前提を念頭に置いてレスポンスの処理を設計する必要があります。また、複数の ajax 呼び出しは、送信された順序で完了することさえ保証されていないことに注意してください。

1つを送信し、それが完了するまで次を送信しないことでajax呼び出しを注文できます。結合されたhtmlを文字列変数に保持し、最後のajax呼び出しの完了関数で、最終的に蓄積されたhtml文字列を追加します体。

ここに別の問題があります。最初の.each()ループの開始時には、これがあります。

html = "<div class=\"page\" id=\"" + page[0] + "\">";

これにより、html変数が再初期化され、既に存在する可能性のある結果が上書きされます。.each() ループの前に一度初期化する必要があります。

于 2012-07-16T01:23:57.023 に答える
1

jsonp リクエストはデフォルトでグローバルではないため、ajaxStop は起動しません。こちらをご覧ください

jsonp リクエストをグローバルとして強制するフィドルを更新しました。http://jsfiddle.net/u42uy/3/

※編集ミス

于 2012-07-16T02:22:44.573 に答える
0

次の手順を実行します。

  • var html = ''後に追加var pages(1 行目);
  • (6 行目)に変更html =します。html +=
  • html = ''後に追加し$("body").append(html + "</div>");ます (41 行目)。

結果:

var pages = [["Page Title 1", ["Page URL 1", "Page URL 2", "Page URL 3"]], ["Page Title 2", ["Page URL 1", "Page URL 2", "Page URL 3"]], ["Page Title 3", ["Page URL 1", "Page URL 2", "Page URL 3"]]];
var html = ''; // ADD THIS

function loadFeeds() {
$.each(pages, function(index, page) {
    $(".pages").append("<a class=\"pagename\" href=\"#" + page[0] + "\">" + page[0] + "</a>");
    html += "<div class=\"page\" id=\"" + page[0] + "\">"; //ADD THE +

    $.each(page[1], function(index, feedUrl) {

    $.ajax({
    type: "GET",
    url: feedUrl,
    processData : true,
    data: {
        tagmode: "any"
        },
    jsonp: "jsonp",
    dataType: "jsonp",
    success: function(data) {
        html += "Some header HTML";

        $.each(data.responseData.feed.entries, function(i,entry) {
            if (entry.image_urls.length === 0) {
                html += "HTML from the data";
            }
            else {
                html += "More HTML";
            }

            if ( i == 34 ) return false;
        });
        html += "Closing tags from the header";
        afterAjax();
    },
            error: function(x,y,z) {
                alert(x.responseText);
            }
        });
    });
        $("body").append(html + "</div>");
        html = ''; // RESET HTML TO NEXT Each
});
于 2012-07-16T01:19:36.307 に答える