0

我有嵌套each循环,但第二个循环中的 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 Pattern或 defereds。在 jQuery 中,这是通过.promise()(Futures/Promises) 或.when()(Deffered) 完成的。

关于全局变量的说明

还值得注意的是,不使用var html = ...会使您的变量成为全局变量;这通常是不受欢迎的。最好$("body").append(html+"</div>")在成功处理程序中移动后也声明htmlvar html.

于 2012-07-16T01:24:14.863 回答
1

除非您的 ajax 调用是同步的(而且我没有看到它们是同步的迹象),否则您的每个循环将在 ajax 调用成功函数运行之前完成并返回。您不能以这种方式构造您的代码。这意味着$("body").append(html + "</div>");它将在 ajax 调用有机会将任何内容添加到您的html变量之前运行。

您需要将 ajax 响应回调视为独立的代码片段,它们在循环完成后的某个时间按自己的时间运行,.each()并在考虑该假设的情况下设计响应的处理。还要记住,多个 ajax 调用甚至不能保证按照它们发送的顺序完成。

您可以通过发送一个而不发送下一个来订购ajax调用,直到该调用完成,将组合的html保存在一个字符串变量中,然后在最后一个ajax调用的完成函数中,将最终累积的html字符串附加到身体。

这是另一个问题。在你的第一个.each()循环开始时,你有这个;

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

这会重新初始化html变量,覆盖可能已经存在的任何结果。您需要在任何 .each() 循环之前对其进行一次初始化。

于 2012-07-16T01:23:57.023 回答
1

ajaxStop 没有触发,因为 jsonp 请求默认不是全局的。看这里

我已经更新了你的小提琴,它强制将 jsonp 请求作为全局请求。http://jsfiddle.net/u42uy/3/

*编辑错字

于 2012-07-16T02:22:44.573 回答
0

执行以下操作:

  • var html = ''在(第 1 行)之后添加var pages
  • 更改html =html +=(第 6 行);
  • 在(第 41 行)html = ''之后添加。$("body").append(html + "</div>");

结果:

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 回答