jquery:基于ajax的搜索 - 浏览器崩溃?

时间:2011-03-20 17:09:37

标签: jquery ajax search

嘿伙计们, 我正在开发一个相当奇怪的基于ajax的搜索模型。搜索实际上并不从服务器检索真实的搜索结果,而是加载网站的站点地图(使用jquery load()方法)并提取其链接。

这实际上非常好,但是有一个小错误可能导致我的浏览器崩溃。

var searchTimer = 0;

$('.s').keyup(function(e) {

    switch (e.keyCode) {
        //case 8:  // Backspace
        case 9:  // Tab
        case 13: // Enter
            doSearch(e.keyCode);
            break;
        case 16: // Shift
        ...
        case 37: // Left
            break;
        case 38: // Up
            doSearch(e.keyCode);
            break;
        case 39: // Right
            break;
        case 40: // Down
            doSearch(e.keyCode);
            break;
        ...
        break;

        default:
        if (searchTimer != 0) {
            clearTimeout(searchTimer);
        }

        searchTimer = setTimeout(function () {
            doSearch(e.keyCode);
        }, 250);
    }

});

function doSearch(keyCode) {

    if ($('.s').val() != '') {

        searchTimer = 0;

        $sr.load('/sitemap/', function() {


        }); // end load

    } else {
        clearsearch(true);
    }
}

我遇到的唯一问题是,一旦我在.s输入字段中输入一个单词并且在250ms内立即将其删除,该网站就会崩溃。

想象一下: 1.)输入为空。 2.)我快速键入“测试”。 3.)doSearch函数甚至没有被触发,我点击cmd -a选择all并删除输入中的文本。

我网站崩溃了!

为什么会发生这种情况?当我只是在输入doSearch()后输入“test”或删除输入时,它确实工作得非常顺畅和精确。它实际上总是有效。就在极少数情况下快速输入并在doSeach()事件中删除键入的文本时,它会崩溃。

知道可能导致什么原因吗?

编辑/更新: 当我将sitemap.html复制到我当前的procets根目录并加载它时,它不会崩溃并且在您的示例中正常工作。一旦我将其更改为url: "sitemap", dataType: "html",,它就会崩溃。我使用mydomain.com/sitemap ...

调用我的站点地图

站点地图的代码如下所示:

    <?php
/**
 * Template Name: Sitemap
 */
?>
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

    <div id="ajax-base">
        <h3>Pages</h3>
            <ul>
                <?php wp_list_pages('title_li=&depth=0&exclude='); ?>
            </ul>
        <h3>Posts</h3>
            <?php $first = 0;?>
            <ul>
            <?php
            $myposts = get_posts('numberposts=-1&offset=$first');
            foreach($myposts as $post) :
            ?>
            <li><a href="<?php the_permalink(); ?>#b"><?php the_title(); ?></a></li>
            <?php endforeach; ?>
            </ul>
        <h3>Categories</h3>
            <ul>
                <?php wp_list_categories('title_li=&orderby=name'); ?>
            </ul>
        <h3>Tags</h3>
            <ul>    
                <?php
                $tags = get_tags();
                foreach ($tags as $tag){
                    $tag_link = get_tag_link($tag->term_id);
                    $html .= "<li><a href='{$tag_link}#b' title='{$tag->name} Tag' class='{$tag->slug}'>";
                    $html .= "{$tag->name}</a></li>";
                }
                echo $html;
                ?>
            </ul>
    </div> <!-- ajax-base -->

<?php endwhile; endif; ?>

抱歉这最后一个问题,但任何想法为什么会有所作为。当我使用此动态/站点地图作为我的搜索基础时,浏览器崩溃。使用静态html页面可以正常工作。

2 个答案:

答案 0 :(得分:4)

我认为您的代码的主要问题是您不会中止之前的待处理ajax调用。如果同时尝试修改两个服务器响应上的$sr元素,浏览器会发生什么?

XMLHttpRequest和新jqXHR都有abort方法,您可以使用。

更新:正如我在评论中所述,jQuery.loadjQuery.ajax调用相比更多,jQuery.html将服务器响应放在页面上。您可以在jQuery.load here(对于jQuery 1.4.4)或here(对于jQuery 1.5.1)的源代码中进行验证。

我为您准备了一个小型演示示例,其中展示了如何直接使用jQuery.ajaxjQuery.html代替jQuery.load。您可以下载完整的项目here

如果演示文稿缓慢的输入框中有一个类型,则会收到以下结果 enter image description here

如果一个类型更快(我打字很慢,所以在服务器上使用1秒超时): enter image description here

如果存在任何待处理的ajax请求,我可以看到我将之前的ajax请求中止到服务器。如果中止,则调用相应(先前)ajax请求的error处理程序,然后abort()函数返回。

我希望如果你遵循这样的方式,你将永远不会遇到你在问题中描述的问题。

为了确保您收到示例,我在下面提供了我在测试演示中使用的完整代码。 JavaScript代码如下:

var jqXHR_Old, $myinput = $('#myinput'),
    $result = $('#result'), $protocol = $('#protocol'),
    logText = function(txt) {
        $protocol.append(txt+"<br/>"); // append or prepend
    },
    doSearch = function(code) {
        var txt = $myinput.val();
        if (txt != '') {
            // send request to the server
            if (jqXHR_Old) {
                // abort the previous request
                logText("aborting...");
                jqXHR_Old.abort();
                jqXHR_Old = null;
            }

            $result.empty();
            logText('sending request to the server with '+
                    '<span style="color:blue;">'+txt+'</span>...');
            jqXHR_Old = $.ajax({
                url: "MySimpleService.svc/GetTestHtmlFragment",
                data: {str:txt},
                dataType: "html",
                success: function (data) {
                    $result.html(data);
                    logText("received from the server: "+data);
                    jqXHR_Old = null;
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    if (textStatus !== "abort" || errorThrown !== "abort") {
                        $result.html("Error Occured!" + " | " + " | " +
                                        textStatus + " | " + errorThrown +
                                        "responseText:<br/>" + XMLHttpRequest.responseText);
                    } else {
                        logText("request aborted.");
                    }
                    jqXHR_Old = null;
                }
            });
        }
    };
$myinput.keyup(function(e) {
    switch (e.keyCode) {
        //case 8:  // Backspace
        case 9:  // Tab
        case 13: // Enter
            doSearch(e.keyCode);
            break;
        case 37: // Left
            break;
        case 38: // Up
            doSearch(e.keyCode);
            break;
        case 39: // Right
            break;
        case 40: // Down
            doSearch(e.keyCode);
            break;

        default:
            doSearch(e.keyCode);
    }
});

HTML就在这里

<fieldset style="float:left">
    <input type="text" id="myinput"/>
</fieldset>
<div style="clear:left">
    <fieldset style="float:left">
       <legend>Results from the server:</legend>
       <div id="result"></div>
    </fieldset>
    <div style="clear:left"/>
    <fieldset style="float:left">
       <legend>Ajax protocol:</legend>
       <div id="protocol"></div>
    </fieldset>
</div>

作为服务器,我使用非常简单的WCF服务和接口

使用System.ServiceModel; 使用System.ServiceModel.Web; 使用System.ServiceModel.Channels;

namespace AjaxLoad {
    [ServiceContract]
    public interface ISimpleService {
        [OperationContract]
        [WebGet]
        Message GetTestHtmlFragment (string str);
    }
}

和实施

using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading;

namespace AjaxLoad {
    [AspNetCompatibilityRequirements (RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class SimpleService : ISimpleService {
        public Message GetTestHtmlFragment (string str) {
            Thread.Sleep (1000);
            return WebOperationContext.Current.CreateTextResponse ("<span style='color:red'>" + str + "</span>",
                "text/html; charset=utf-8",
                Encoding.UTF8);
        }
    }
}

我只用Thread.Sleep模拟慢速请求处理,等待1秒钟。我使用SVC文件免费实现,因此用作web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>

    <system.serviceModel>
        <standardEndpoints>
            <webHttpEndpoint>
                <!-- the "" standard endpoint is used by WebServiceHost for auto creating a web endpoint. -->
                <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"  />
            </webHttpEndpoint>
        </standardEndpoints>
        <behaviors>
            <serviceBehaviors>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true">
            <serviceActivations>
                <add relativeAddress="MySimpleService.svc" service="AjaxLoad.SimpleService"
                     factory="System.ServiceModel.Activation.WebServiceHostFactory" />
            </serviceActivations>
        </serviceHostingEnvironment>
    </system.serviceModel>
</configuration>

作为项目的“引用”需要三个依赖程序集:System,System.ServiceModel,System.ServiceModel.Web。

答案 1 :(得分:0)

试试这个:

var searchTimer; //define the scope of searchTimer and set it to null
/* ...code...*/

if (searchTimer != null) {
    clearTimeout(searchTimer);
}

超时的ID始终从0开始,随着更多定时器的创建而上升。