【问题标题】:Javascript Instance Variable Syntax (AJAX page refresh)Javascript 实例变量语法(AJAX 页面刷新)
【发布时间】:2011-02-05 09:18:30
【问题描述】:

我在使用 Javascript 实例变量时遇到了困难。我正在尝试一种简单的方法来刷新聊天页面,寻找新消息。 AJAX 调用提供mid,或要返回的最低消息ID。这允许调用仅询问最近的消息,而不是所有消息。

MessageRefresher.prototype._latest_mid;

function MessageRefresher(latest_mid) {
    this._latest_mid = latest_mid; // it thinks `this` refers to the MessageRefresher object
}

MessageRefresher.prototype.refresh = function () {
    refreshMessages(this._latest_mid); // it thinks `this` refers to the window
    this._latest_mid++;
}

function refreshMessages(latest_mid) {
    $.getJSON('API/read_messages', { room_id: $.getUrlVar('key'), mid: latest_mid }, function (messages) {
        for (var i = 0; i < messages[0].length; i++) {
            var newChild = sprintf("<li>%s: %s</li>", messages[1][i], messages[0][i]);
            $("#messages").append(newChild);
        }
    });

    var messageRefresher = new MessageRefresher(0);
    setInterval(messageRefresher.refresh, 1000);

这会导致所有消息被一遍又一遍地打印出来。

我知道它还有其他错误,但我现在要解决的主要问题是实例变量的使用。或者我应该采取其他方法吗?

更新:更新了代码以反映答案,但它仍然不起作用:

$(document).ready(function () {

    var messageRefresher = new MessageRefresher(0);
    setInterval($.proxy(messageRefresher, "refresh"), 1000);

});

function MessageRefresher(latest_mid) {
    this._latest_mid = latest_mid; // it thinks `this` refers to the MessageRefresher object
}

MessageRefresher.prototype.refresh = function () {
    refreshMessages(this._latest_mid); // it thinks `this` refers to the window
}

function refreshMessages(latest_mid) {
    var refresher = this;
    $.getJSON('API/read_messages', { room_id: $.getUrlVar('key'), mid: latest_mid }, function (messages) {
        if (messages != null) {
            $("#messages-loading-msg").hide();
            for (var i = 0; i < messages[0].length; i++) {
                var newChild = sprintf("<li>%s: %s</li>", messages[1][i], messages[0][i]);
                $("#messages").append(newChild);
            }
        }
        else {
            $("#messages-loading-msg").text("No messages here. Say anything...");
        }

        refresher._latest_mid = messages[2];
    });
    }

我仍然做错了什么? this 真的指的是messageRefresher,还是proxy

更新 2: 越来越近了,但还不够:

$(document).ready(function () {

    $("#no-js-warning").empty();

    messageRefresher = new MessageRefresher(0);
    setInterval($.proxy(messageRefresher, "refresh"), 1000);

});

function MessageRefresher(latest_mid) {
    this._latest_mid = latest_mid; 
}

MessageRefresher.prototype.refresh = function () {
    var refresher = this;
    $.getJSON('API/read_messages', { room_id: $.getUrlVar('key'), mid: refresher._latest_mid }, function (messages) {
        if (messages != null) {
            $("#messages-loading-msg").hide();
            for (var i = 0; i < messages[0].length; i++) {
                var newChild = sprintf("<li>%s: %s</li>", messages[1][i], messages[0][i]);
                $("#messages").append(newChild);
            }
        }
        else {
            $("#messages-loading-msg").text("No messages here. Say anything...");
        }

        refresher._latest_mid = messages[2]; // break here
    });
}

上面的代码进行了两次 AJAX 调用,然后停止。此外,当我在上面标记的“break here”行上中断时,Firebug 不会显示refresher_latest_mid 的值。我是否将refresher 正确传递到闭包中?

更新 3: 现在它不再停止进行 AJAX 调用。也许它有时会进行多次调用的原因是setInterval() 在第一个请求返回之前触发了多个请求并更新了_latest_mid

如何使用 JQuery Ajax 框架来防止这种情况发生?

【问题讨论】:

  • 我不做 jquery,所以我不知道新的 $.proxy 方法的 api,但我保证我的答案在任何框架中都有效。
  • 我已经更新了我的答案。您可能想四处寻找一些关于上下文绑定如何在 Javascript 中工作的优秀教程;我输入了一个简短的摘要,但其他人做得比我好。
  • 也许您可以在$.getJSON 的响应处理程序中添加一个“setTimeout”调用,而不是使用“setInterval”。换句话说,以超时启动它,然后每当您收到一条消息时,您设置另一个超时以再次执行此操作。这样一来,在完成上一条消息之前,您甚至都不会考虑收到另一条消息。
  • hmm...setTimeout 似乎只触发了一次调用。

标签: javascript jquery ajax oop syntax


【解决方案1】:

试试这个:

setInterval($.proxy(messageRefresher, "refresh"), 1000);

问题是您需要确保您的对象(messageRefresher)被用作调用“刷新”函数的“上下文”。它被声明为原型的一部分这一事实并不能确保“this”始终是对象的实例。事实上,“这个”几乎可以是任何东西。

jQuery 中的(相当新的)“代理”方法返回对辅助函数的引用,该函数将使用您需要的对象作为上下文(即“刷新”中的“this”)调用您的函数(“刷新”) ")。

还有第一行,你只是提到了那个实例变量,你不需要那个;它并没有真正做任何事情。

编辑更多解释。

任何 Javascript 函数中的“this”变量,无论它是如何声明或在何处声明的,在每次不同的调用时都会获得其值。它不是功能的永久部分;实际上,它就像传递给函数的有点特殊的参数。

在您上面的例子中,您在传递给$.getJSON 的函数中有一行代码引用“this”。您想要的是“this”引用表示您的“messageRefresher”对象,对吗?好吧,就目前而言,它没有理由具有那个价值。

我不知道您为什么将“refreshMessages”拆分成那样。使其成为“刷新”方法。然后,一开始就保存“this”指针,你就可以从$.getJSON处理程序中引用回来:

MessageRefresher.prototype.refresh = function () {
  var refresher = this;
  $.getJSON('API/read_messages', { room_id: $.getUrlVar('key'), mid: latest_mid }, function (messages) {
    if (messages.length > 0) {
        $("#messages-loading-msg").empty();
        for (var i = 0; i < messages[0].length; i++) {
            var newChild = sprintf("<li>%s: %s</li>", messages[1][i], messages[0][i]);
            $("#messages").append(newChild);
        }
        refresher._latest_mid = messages[2];
    }
    else {
        $("#messages-loading-msg").text("No messages here. Say anything...");
    }

  });
 }  

【讨论】:

    【解决方案2】:

    这是因为您正在使用该功能并将其分配给一个区间。您已将函数对象传递给 setInterval,因此它不会跟踪其所有者。

    从区间调用的函数将在全局对象的范围内。这就是你解决这个问题的方法。

    setInterval(function() {
        //this == window normally
    
        messageRefresher.refresh();
        //method invocation, so refresh will be bound
        //to the messageRefresher instance
    }, 1000);
    

    【讨论】:

    • 这似乎不行。 Firebug 抱怨您的示例是“无用的 setInterval 调用”,返回类型为 messageRefresher.refresh() != 一个函数。把它放在引号中会给出错误“messageRefresher 未定义”。
    • 什么?我知道这行得通。我只是仔细检查了一下,工作得很好。你不需要任何报价。您是否遗漏了匿名函数部分?不要这样做:setInterval(messageRefresher.refresh(), 1000); 尝试使用从刷新返回的函数来设置间隔,但显然没有。
    猜你喜欢
    • 2013-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多