javascript - 避免闭包引起的 jQuery Mobile 内存泄漏

标签 javascript jquery-plugins memory-leaks jquery-mobile closures

我正在尝试创建一个供我自己使用的 jQuery 插件,该插件可用于使用单个命令设置 jQuery 移动对话框的处理程序,例如:$('#dialog').setup_dialog({ callback:回调函数});

但是,由于其中的闭包,我的处理程序有相当明显的内存泄漏:

$.fn.setup_dialog = function( options ) {
    var settings = $.extend({
        callback : 0
    }, options);
    var that = this;

    return this.live('pagebeforeshow', function(event, ui) {
        console.log("outside");
        $('form', that).submit( function(e) {
            var $inputs = $('form :input', that); // get all form inputs

            var values = {};
            $inputs.each(function() {
                values[this.name] = $(this).val();
            });

            that.dialog('close');

            if ( settings.callback && typeof(settings.callback) === "function" ) {
                $('#'+ui.prevPage[0].id).live('pagebeforeshow', function() {
                    settings.callback(values, that);
                    console.log("inside");
                });
            }

            return e.preventDefault();
        });
    });
}; /* setup_dialog */

如果你运行上面的代码,你会看到“inside”和“outside”先打印一次,然后打印三次(一次提交两次),然后六次(一次提交三次),等等。

该代码的目的是在 jQuery Mobile 对话框出现时将事件处理程序附加到它将捕获表单提交,收集所有表单值,然后将它们传递给将修改原始页面的回调函数(启动对话框)。

请注意,由于 jQuery Mobile 使用 AJAX 在页面之间切换的方式,我需要使用 .live 来绑定(bind)事件(.bind 或 .one 不起作用)。

我有什么想法可以避免事件累积(并且可能还稍微清理一下代码)吗?

最佳答案

您正在将事件处理程序绑定(bind)到其他事件处理程序中。并且外部事件处理程序不是唯一事件(它们不止一次发生),这意味着您的内部事件处理程序被绑定(bind)了不止一次。

一个好的修复方法是从 pagebeforeshow 事件处理程序中删除 submit 事件处理程序,并将其放在 pagecreatepageinit 事件处理程序(这些是唯一的,每个对话框只运行一次)。

如果您想保留当前的逻辑,那么您可以在事件处理程序运行时解除绑定(bind),这样您就不会堆叠多个执行相同操作的事件处理程序:

$.fn.setup_dialog = function( options ) {
    var settings = $.extend({
        callback : 0
    }, options);
    var that = this;

    return this.live('pagebeforeshow', function(event, ui) {
        console.log("outside");
        $('form', that).submit( function(e) {
            var $inputs = $('form :input', that); // get all form inputs

            var values = {};
            $inputs.each(function() {
                values[this.name] = $(this).val();
            });

            that.dialog('close');

            if ( settings.callback && typeof(settings.callback) === "function" ) {
                $('#'+ui.prevPage[0].id).live('pagebeforeshow', function() {
                    settings.callback(values, that);
                    console.log("inside");

                    $(this).die('pagebeforeshow');//NEW, unbind the pagebeforeshow event handler for this element
                                                  //since it will be bound the next time the dialog is shown anyway
                });
            }

            $(this).die('submit');//NEW, unbind the submit event handler for this form 
                                  //since it will be bound the next time the dialog is shown anyway

            return e.preventDefault();
        });
    });
}; /* setup_dialog */

这是 .die() 的文档:http://api.jquery.com/die/

关于javascript - 避免闭包引起的 jQuery Mobile 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8993101/

相关文章:

java - java程序执行后如何释放内存

javascript - 如何使用 CSS 将过渡应用到下一张幻灯片

javascript - 获取类别列表以保留显示在我的下拉菜单上

javascript - 异步函数是 JavaScript 中函数的子集吗?

JQuery Datepicker 堆叠月份和年份

javascript - 如何让 jQuery UI 布局插件发挥作用?

javascript - 我们是否需要手动清理闭包中未引用的变量?

javascript - 如何制作像 Youtube 中那样具有标记功能的文本区域

jquery等高插件添加边距

iOS,未知进程,未知崩溃