简体   繁体   English

JavaScript回调函数问题

[英]Javascript callback function issue

Background 背景

I'm writing an asynchronous comment system for my website, after reading plenty of tutorials on how to accomplish this I started building one from scratch. 在为我的网站编写了一个异步评论系统之后,我阅读了许多有关如何完成此操作的教程,然后我从头开始构建一个评论系统。 The comments are pulled using a JSON request and displayed using Javascript (jQuery). 使用JSON请求提取注释,并使用Javascript(jQuery)显示注释。 When the user adds a new comment it goes through the hoops and finally is sent via AJAX to the backend where it's added to the database. 当用户添加新评论时,它会经过箍,最后通过AJAX发送到后端,在此将其添加到数据库。 In the success section of the AJAX request I had the script empty the comments, then repull the new list (including the new post) and redisplay them. 在AJAX请求的成功部分,我让脚本清空了注释,然后重新拉动新列表(包括新帖子)并重新显示它们。

Problem 问题

While that was all nice, since it's making the page much shorter, then much longer it messes up where the user is viewing the page. 尽管这一切都很好,但是由于它使页面更短,所以更长的时间会弄乱用户查看页面的位置。 I wanted to have it readjust the page back down to the end of the comment list (where the add comment form is). 我想让它重新调整页面,使其向下回到注释列表的末尾(添加注释表单所在的位置)。 It also re-enables the add button, which was disabled when the clicked it to prevent impatient people from spamming. 它还会重新启用添加按钮,单击该按钮时将其禁用,以防止不耐烦的人发垃圾邮件。

$('#commentList').empty();
getComments('blog', $('input#blogId').val());
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');

While this worked all well and good in theory, it seemed that the browser was getting ahead of itself and processing the window.location before the getComments function was done. 尽管从理论上讲这一切都很好,但是在完成getComments函数之前,浏览器似乎正在超越自身并处理window.location。 So I read a little more and googled it and it seemed people were saying (for similar problems) to use callback functions, so I came up with this: 因此,我阅读了更多内容并在Google上搜索了一下,似乎人们在说(针对类似问题)使用回调函数,因此我想到了:

$('#commentList').empty();
getComments('blog', $('input#blogId').val(), function() {
    window.location = "#addComment";
    $('#comAdd').removeAttr('disabled');
});

This generates no javascript errors according to FireFox, but nothing within the callback function is working, it's not re-enabling the button nor changing the window.location. 根据FireFox,这不会产生任何JavaScript错误,但是回调函数中的任何内容都无法正常工作,它既没有重新启用按钮,也没有更改window.location。

Any ideas? 有任何想法吗? Better ways to go about it? 更好的方法吗? Do I have a glaring typo that I can't seem to see? 我有看不见的错字吗?

Thanks! 谢谢!

Update 更新

I was under the impression the callback functions were a standard thing you could use. 我印象中,回调函数是您可以使用的标准功能。

function getComments(type, id)
{

    $.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
        for (var x = 0; x < data.length; x++)
        {
            var div = $("<div>").addClass("comment").appendTo("#commentList");
            var fieldset = $("<fieldset>");
            var legend = $("<legend>").addClass("commentHeader");
            if ( data[x].url == "" )
            {
                legend.text((x+1) + ' - ' + data[x].name);
            }
            else
            {
                $("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
            }
            legend.appendTo(fieldset);
            $("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
            $("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
            fieldset.appendTo(div);
        }
    });

}

This is called on document ready. 这被称为准备文档。 Pulling all the comments and displaying them inside the #commentList div. 拉出所有注释并将其显示在#commentList div中。 When the user submits his/her comment it performs an AJAX request to a PHP script that adds the new comment to the database, upon success of this I have this: 当用户提交他/她的注释时,它将对PHP脚本执行AJAX请求,该脚本会将新注释添加到数据库中,一旦成功,我将获得以下信息:

$('#commentList').empty();
getComments('blog', $('input#blogId').val());
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');

Deletes all the comments from the page. 从页面删除所有评论。 Uses JSON to request the comments again (including the users new one). 使用JSON再次请求评论(包括用户的新评论)。 Moves the page to the #addComment anchor, which is where their new comment would be displayed. 将页面移至#addComment锚点,该锚点将显示其新注释。 Re-enables the add comment button. 重新启用添加评论按钮。

The problem is that the browser does the window.location line before the getComments function is done rendering all the comments, so as the page grows the user isn't looking anywhere near their new comment. 问题在于浏览器在完成getComments函数的呈现所有注释之前先执行window.location行,因此随着页面的增长,用户不会在新注释附近寻找任何地方。

I expect here the problem is your getComments() function (for which more detail is required). 我希望这里的问题是您的getComments()函数(需要更多详细信息)。 You're supplying a third argument being a callback but does the function actually use a callback? 您提供的第三个参数是回调,但是该函数实际上使用回调吗? What is it doing? 到底在做什么

Certain jQuery functions provide callbacks but this isn't an automatic feature. 某些jQuery函数提供回调,但这不是自动功能。 If you're waiting for a user to type a comment you need to trigger the relevant event when they click "Done" or whatever they do. 如果您在等待用户键入评论,则需要在他们单击“完成”或执行任何操作时触发相关事件。

Ok, try this: 好的,试试这个:

function get_comments(type, id, callback) {
  $.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
    for (var x = 0; x < data.length; x++) {
      var div = $("<div>").addClass("comment").appendTo("#commentList");
      var fieldset = $("<fieldset>");
      var legend = $("<legend>").addClass("commentHeader");
      if ( data[x].url == "" ) {
        legend.text((x+1) + ' - ' + data[x].name);
      } else {
        $("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
      }
      legend.appendTo(fieldset);
      $("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
      $("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
      fieldset.appendTo(div);
      if (typeof callback != 'undefined') {
        callback();
      }
    }
  });
}

Note: the difference here is that a third argument is supplied to get_comments() which is a callback that'll be called at the end of your $.getJSON() callback. 注意:这里的区别是第三个参数提供给get_comments(),这是一个回调,将在$ .getJSON()回调的末尾被调用。 That'll give you the proper ordering you want. 这样可以为您提供所需的正确订购。

I might also suggest not constructing the HTML like that but including it in your page and hiding/unhiding it as necessary. 我可能还会建议不要像那样构造HTML,而是将其包含在页面中并根据需要隐藏/取消隐藏它。 It tends to be much more performant that dynamic HTML and have less issues (eg new HTML, unless you use $().live() will not have relevant event handlers). 它比动态HTML具有更高的性能,并且问题更少(例如,新的HTML,除非您使用$()。live()不会具有相关的事件处理程序)。

Edit: Made the callback optional as per the comments. 编辑:根据评论将回调设为可选。 With the above code you can call the function without or without the callback. 使用以上代码,您可以在没有回调或没有回调的情况下调用该函数。

Simple. 简单。 Re-enable the button and go to the anchor after you receive the request and process the information. 收到请求并处理信息 ,请重新启用按钮并转到锚点。 Like so: 像这样:

function getComments(type, id)
{
    // ADDED
    $('#commentList').empty();

    $.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
        for (var x = 0; x < data.length; x++)
        {
                var div = $("<div>").addClass("comment").appendTo("#commentList");
                var fieldset = $("<fieldset>");
                var legend = $("<legend>").addClass("commentHeader");
                if ( data[x].url == "" )
                {
                        legend.text((x+1) + ' - ' + data[x].name);
                }
                else
                {
                        $("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
                }
                legend.appendTo(fieldset);
                    $("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
                    $("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
                fieldset.appendTo(div);
        }

        // ADDED
        window.location = "#addComment";
        $('#comAdd').removeAttr('disabled');
    });
}

Personal opinion: rather than fetching all comments, why not fetch comments from a certain date? 个人意见:为什么不获取特定日期的评论,而不是获取所有评论? When you load the page, include a server time in the response. 加载页面时,在响应中包括服务器时间。 The Javascript uses this to query behind the scenes (to automatically check for new comments). Javascript使用它在幕后进行查询(以自动检查新评论)。 The JSON response includes a new server time, which is used in the next response. JSON响应包括一个新的服务器时间,该时间将在下一个响应中使用。

How would you handle deleted comments? 您将如何处理已删除的评论? Easy: have a deleted_on column in your database table, query it, and spit that out in the JSON response along with new posts. 轻松:在您的数据库表中有一个deleted_on列,对其进行查询,然后将其与新帖子一起吐到JSON响应中。

Suggestion: instead of #addcomment , ID comments by timestamp. 建议:通过时间戳ID注释代替#addcomment

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM