【问题标题】:Javascript/JQuery: Reload a page AFTER two functions have completedJavascript/JQuery:两个功能完成后重新加载页面
【发布时间】:2014-02-26 20:11:08
【问题描述】:

我有一个保存按钮,它调用一个函数来打开一个带有两个按钮的模式对话框; “保存时间线”和“取消”。 “保存时间线”按钮在页面需要重新加载之后调用两个函数。我尝试了几种不同的方法来完成这项工作......

1 只是务实地调用函数:

    function genSaveTimelinesModal() {
    $("#saveTimelineDialog").dialog({
        resizable: false,
        height: 250,
        modal: true,
        buttons: {
            "Save timelines": function() {
                editSavedTimelines(); 
                saveTimelines();
                $(this).dialog("close");
                location.reload();
            },
            Cancel: function() {
                $(this).dialog("close");
            }
        }
    });
}

2 设置回调:

function genSaveTimelinesModal() {
    $("#saveTimelineDialog").dialog({
        resizable: false,
        height: 250,
        modal: true,
        buttons: {
            "Save timelines": function() {
                editSavedTimelines(saveTimelines()); 

                location.reload();
            },
            Cancel: function() {
                $(this).dialog("close");
            }
        }
    });
}

3 使用 JQuery $.when().do():

    function genSaveTimelinesModal() {
    $("#saveTimelineDialog").dialog({
        resizable: false,
        height: 250,
        modal: true,
        buttons: {
            "Save timelines": function() {
                $.when(editSavedTimelines(), saveTimelines()).do(location.reload());
            },
            Cancel: function() {
                $(this).dialog("close");
            }
        }
    });
}

我的问题,在所有三个尝试中,都是在单击“保存时间线”按钮时出现的......页面重新加载并且没有运行任何功能。当我从每个示例中提取 location.reload() 调用时,函数会按我想要的方式运行。

有没有办法只在功能完成后重新加载页面?

作为参考,这里是我调用的函数:

function saveTimelines() { 
    console.log("start save");
    for (i=1; i < timelineIndex + 1; i++) {
        var dow = startdow;
        var clientValue = $("#clientNameSelect" + i).val();
        var projectValue = $("#projectSelect" + i).val();
        var taskValue = $("#taskSelect" + i).val();
        var billingValue = $("#billingSelect" + i).val();
        var activityValue = $("#activitySelect" + i).val();
        var stateValue = $("#states" + i).val();
        var sundayValue = $("#sun" + i).val();
        var mondayValue = $("#mon" + i).val();
        var tuesdayValue = $("#tue" + i).val();
        var wednesdayValue = $("#wed" + i).val();
        var thursdayValue = $("#thu" + i).val();
        var fridayValue = $("#fri" + i).val();
        var saturdayValue = $("#sat" + i).val();



        $.ajax({
            type: "GET",
            url:"biqqyzqyr?act=API_DoQuery&query={'6'.EX.'" + projectValue + "'}AND{'16'.TV.'" + currUserEmail + "'}&clist=3&includeRids=1&fmt=structured",
            dataType: "xml",
            success: function (xml) {
                $(xml).find("record").each(function () {
                    var resourceMap = new Array();
                    $(this).children().each(function () {
                        var name = $(this).attr("id");
                        var value = $(this).text();
                        resourceMap[name] = value;
                    });
                    resourceRecords.push(resourceMap);
                });
                console.log("hi");
                var resourceRId = '3';
                for (var j = 0; j < resourceRecords.length; j++) {
                    resourceOptions = resourceRecords[j][resourceRId];
                    console.log(resourceOptions);
                }

                $.ajax({
                    type: "GET",
                    url: "biha4iayz?act=API_AddRecord&_fid_12=" + dow + "&_fid_36=" + clientValue + "&_fid_9=" + projectValue + "&_fid_7=" + taskValue + "&_fid_10=" + billingValue + "&_fid_15=" + activityValue + "&_fid_11=" + stateValue + "&_fid_13=" + sundayValue + "&_fid_57=" + mondayValue + "&_fid_58=" + tuesdayValue + "&_fid_59=" + wednesdayValue + "&_fid_60=" + thursdayValue + "&_fid_61=" + fridayValue + "&_fid_62=" + saturdayValue + "&_fid_17=" + resourceOptions,
                    dataType: "xml",
                    success: function () {
                        console.log(i+ "new")
                    },
                    fail: loadFail
                });

            },
            fail: loadFail
        });
    }

    alert(timelineIndex+savedTimelineIndex+" timelines have been saved to the system...");

}



function editSavedTimelines(callback) {
    console.log("start edit");
    for (j=1; j < savedTimelineIndex + 1; j++) {
        var dow = startdow;
        var savedRId = $("#recordsaved" + j).val();
        var sundayValue = $("#sunsaved" + j).val();
        var mondayValue = $("#monsaved" + j).val();
        var tuesdayValue = $("#tuesaved" + j).val();
        var wednesdayValue = $("#wedsaved" + j).val();
        var thursdayValue = $("#thusaved" + j).val();
        var fridayValue = $("#frisaved" + j).val();
        var saturdayValue = $("#satsaved" + j).val();

        console.log(savedRId);



     $.ajax({
        type: "GET",
        url: "biha4iayz?act=API_EditRecord&rid=" + savedRId + "&_fid_13=" + sundayValue + "&_fid_57=" + mondayValue + "&_fid_58=" + tuesdayValue + "&_fid_59=" + wednesdayValue + "&_fid_60=" + thursdayValue + "&_fid_61=" + fridayValue + "&_fid_62=" + saturdayValue,
        dataType: "xml",
        success: function () {

        },
        fail: loadFail
    });



}

}

【问题讨论】:

  • ajax 中的嵌套调用 saveTimelines 使其特别棘手。解决方案 2 和 3 的组合可以工作。但是使用when 的重要一点是,您需要您的函数返回由$.ajax 返回的xhr
  • editSavedTimelines()saveTimelines()可以并行运行,还是需要在第二个开始之前完成?
  • 它们可以按任何顺序完成。
  • 你确定你做了一个同步 ajax 调用,因为 saveTimelines 和 editSaveTimelines 肯定会被调用,但问题是如果 ajax 请求是异步的,那么 location.refresh 会超载它
  • 我有类似的功能,只需一次调用即可运行,并且 location.reload 不会使其过载。

标签: javascript jquery


【解决方案1】:

你使用when 的问题是你的两个函数都没有返回任何东西。您的电话基本上相当于:

$.when(undefined, undefined)

您的 saveTimelines 函数是更复杂的函数,因为您在第一个回调中进行了第二个 ajax 调用。更糟糕的是,这些 ajax 调用是循环的。 因此,在循环的每次迭代的内部 ajax 调用完成之前,您的函数不会“完成”。

我强烈建议尝试完全重新设计它以简化事情。如果您可以消除循环以及嵌套的 ajax 调用,这会容易得多。

话虽如此,让我们看看如何克服这个问题。首先处理内部 ajax 调用的问题,您可以通过创建自己的延迟对象来解决这个问题。像这样的东西(暂时忽略循环):

function saveOneTimeline(/* any params here, such as i */) {

    // create a deferred object which will be returned by this function and resolved once all calls are complete
    var def = $.Deferred();

    /* ... */

    $.ajax({
        /* ... */    
        success: function (xml) {
            /* ... */                
            $.ajax({
                /* ... */    
                success: function () {
                    // we are done, resolve the deferred object
                    def.resolve();
                }
            });
        }
    });

    // return the deferred object so that the calling code can attach callbacks/use when
    return def;
}

最后,我们之前的方法可以在循环中调用,将返回的延迟对象放入一个数组中,然后使用when 返回一个承诺,该承诺只有在所有延迟都解决后才会解决。它看起来像这样:

function saveTimelines() {
    // an array to store all of the deferreds
    var defs = [];

    for (i=1; i < timelineIndex + 1; i++) {
        defs.push(saveOneTimeline(i));
    }

    // call when on the array of deferred objects and return the resulting promise object
    return $.when.apply($, defs);
}

由于您没有嵌套的 ajax 调用,因此您的 editSavedTimelines 稍微不那么复杂。但是,您仍然有一个循环。可以使用非常相似的方法,只是辅助函数可以简单地直接返回 ajax 调用返回的对象。

如您所见,这一切都非常复杂。相反,尝试消除一些复杂性以避免不得不达到这些长度可能是一个更好的主意。也许如果您可以在一个循环中进行一次批量 ajax 调用而不是多次调用,然后允许后端代码处理分离。

【讨论】:

  • +1 解释为什么现有代码不起作用是一个很好的接触,即使这与其他答案的解决方案相对相同。
  • +1 由于解释,可能比我的答案更好。
【解决方案2】:

这应该适合你。它为 for 循环中的 for ajax 调用使用一组 Deferred 对象,并在所有这些都完成时有一个最终的 deferred 对象。外部函数监听那些延迟对象的完成。请注意,我已经剪掉了很多不相关的代码,并将您的 ajax 调用从成功回调更改为 .done()

function genSaveTimelinesModal() {
    $("#saveTimelineDialog").dialog({
        resizable: false,
        height: 250,
        modal: true,
        buttons: {
            "Save timelines": function() {
                $.when(editSavedTimelines(), saveTimelines()).done(function() {
                    location.reload();
                });
            },
            Cancel: function() {
                $(this).dialog("close");
            }
        }
    });
}

function saveTimelines() {

    var finalDef = $.Deferred();

    var defs = [];
    for (i=1; i < timelineIndex + 1; i++) {

        var def = $.Deferred();
        defs.push(def);

        $.ajax({...}).done(function(xml) {

            $.ajax({...}).done(function() {

                def.resolve(true);

            });

        });        
    }

    $.when.apply(null, defs).done(function() {
        finalDef.resolve();
    });

    return finalDef.promise();

}

function editSavedTimelines() {

    var finalDef = $.Deferred();

    var defs = [];
    for (j=1; j < savedTimelineIndex + 1; j++) {    

        var def = $.Deferred();
        defs.push(def);

        $.ajax({...}).done(function() {
            def.resolve(true); 
        });
    }

    $.when.apply(null, defs).done(function() {
       finalDef.resolve(true); 
    });

    return finalDef.promise();
}

【讨论】:

  • 在写我的答案时被拉开,并没有意识到我离开时你的非常相似的答案已经发布。 +1 - 出于好奇,是否有理由将 true 传递给 def.resolve
  • @JamesMontagne 只是个人喜好......我喜欢那里有一些真实的价值。
  • 感谢您的快速响应,正如@JamesMontagne 建议的那样,我可能应该完全重新设计电话。时间是一个障碍,所以我必须处理我目前拥有的东西。我尝试实现这个答案并且页面正在重新加载,但只有 editSaveTimelines() 正在运行。 link 这是我的实现,以防我错过了什么。再次感谢您的回复。
  • @Tabaker78 与提出的实际问题无关,但您似乎也有一个循环问题的闭包。很好地阅读这里:stackoverflow.com/questions/750486/… 当您进行内部 ajax 调用时,您的变量将被重新分配,因此每个请求只会发送最后一组值。
猜你喜欢
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 2018-01-20
  • 2012-02-08
  • 2022-12-19
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多