中止以前的XMLHttpRequest

时间:2014-12-10 20:29:01

标签: javascript xmlhttprequest

我有一个搜索框,我想在立即输入时显示搜索结果;但是在快速打字时我遇到了问题。

JavaScript的:

function CreateXmlHttp() {
    var xmlhttp;
    try {
        xmlhttp = new XMLHttpRequest();
    } catch (e) {
        try {
            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
        }catch (e) {
            try {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {
                alert("your browser doesn't support ajax");
                return false;
            }
        }
    }
    return xmlhttp;
}
function searchfunc(value) {
    if (value!='') {
        var xmlhttp = CreateXmlHttp();
        xmlhttp.open('GET','http://example.com/ajax/instant_search.php?q='+value,true);
        xmlhttp.send(null);
        xmlhttp.onreadystatechange=function() {
            if (xmlhttp.readyState==4 && xmlhttp.status==200) {
                document.getElementById('search_result').innerHTML = xmlhttp.responseText+'<li><a href="http://example.com/search.php?q='+value+'">full search for <strong>'+value+'</strong></a></li>';
            }
        }
    } else document.getElementById('search_result').innerHTML = '';
}

HTML:

<input id="search_box" type="text" placeholder="type to search..." onkeyup="searchfunc(this.value)">
<ul id="search_result"></ul>

如何在新的按键上中止以前的XMLHttpRequest?

2 个答案:

答案 0 :(得分:0)

如果您要中止该请求,您可能会在发现用户仍在键入时首先阻止该请求被发送。

var timeout, timer = 150;
function searchfunc(value) {
    clearTimeout(timeout);
    setTimeout(function () {
        if (value!='') {
            var xmlhttp = CreateXmlHttp();
            xmlhttp.open('GET','http://example.com/ajax/instant_search.php?q='+value,true);
            xmlhttp.send(null);
            xmlhttp.onreadystatechange=function() {
                if (xmlhttp.readyState==4 && xmlhttp.status==200) {
                    document.getElementById('search_result').innerHTML = xmlhttp.responseText+'<li><a href="http://example.com/search.php?q='+value+'">full search for <strong>'+value+'</strong></a></li>';
                }
            }
        } else document.getElementById('search_result').innerHTML = '';
    }, timer);
}

这将做的是当用户按下一个键时,启动一个等待150ms的setTimeout。如果在150ms内再次触发该功能,则清除并重新启动该间隔。一旦间隔最终完成,就会发出ajax请求。

这与使用中止相同,除了服务器没有被ajax请求轰炸的事实,无论如何你都会中止,并且请求会增加150ms的延迟。

有些库可以更好地处理这个问题,例如http://benalman.com/projects/jquery-throttle-debounce-plugin/(它不需要jQuery)

使用该插件,您可以每timer ms发送不超过1个请求,导致第一个密钥始终发送请求,而另一个密钥在timer ms过去之前未发送,给你一个更实时的结果。

答案 1 :(得分:0)

在这里,我将分享我在stencilsjs项目中为实现这种情况所做的一些概述,

首先,我为项目创建了单独的xmlApi.ts通用文件,并在其中编写了以下代码

// common XMLHttpRequest for handling fetch request 
// currently using this XMLHttpRequest in search component to fetch the data
let xmlApi
// Create the XHR request
const request = new XMLHttpRequest()
const fetchRequest = (url: string, params: any) => {
// Return it as a Promise
 return new Promise((resolve, reject) => {
// Setup our listener to process compeleted requests
request.onreadystatechange = () => {

  // Only run if the request is complete
  if (request.readyState !== 4) { return }

  // Process the response
  if (request.status >= 200 && request.status < 300) {
    // If successful
    resolve(request)
  } else {
    // If failed
    reject({
      status: request.status,
      statusText: request.statusText
    })
  }
}
// If error
request.onerror = () => {
  reject({
    status: request.status,
    statusText: request.statusText
  })
}
// Setup our HTTP request
request.open(params.method, url, true)

// Setup our HTTP request headers
if (params.headers) {
  Object.keys(params.headers).forEach(key => {
    request.setRequestHeader(key, params.headers[key])
  })
}

   // Send the request
   request.send(params.body)
 })
}
xmlApi = {
// exporting XMLHttpRequest object to use in search component to abort the previous fetch calls
  request,
  fetchRequest
}
export default xmlApi

第二,我已经通过onTextInput方法传递了 event 对象,以使用event.target.value

获得输入值。

HTMl:

<input id="search_box" type="text" placeholder="type to search..." 
      onInput={event => { this.onTextInput(event) }}/>

示例HTML进行建议:

这里基于showSuggestionListFlag,我已经显示了搜索建议列表,还使用了CSS来正确对齐div并正确输入标签

<div class={'search-result ' + (this.showSuggestionListFlag ? 'show' : '')}>
      <ul class="dropdown-list">
        {this.responseData && this.responseData.map((item, index) => (
          <li class="list-element">{item} </li>
        ))}
      </ul>
    </div>

在我的ts代码中,我导入了我的xmlApi

这里我刚刚从代码中编写了一些逻辑代码,我还使用了asyncawait来处理项目代码中的承诺/拒绝,根据您的代码,您可以处理自己的承诺/拒绝  代码:

import xmlApi from './xmlApi'
onTextInput (event) { // first created bodydata here using `event.target.value`
const opts = {
  method: 'POST',
  body: bodyData,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  }
}
try {
  // aborting the previous xhr request call
  if (xmlApi.request) {
    xmlApi.request.abort()
  }
  const responseData = xmlApi.fetchRequest(endPointUrl, opts)
    .then(data => {
      consolep.log(`xhr request success`)
      return JSON.parse(data['response'])
    })
    .catch(error => {
      console.log.debug(`xhr request cancelled/failed : ${JSON.stringify(error)}`)
    }) //use responseData
if(responseData){this.showSuggestionListFlag = true}
} catch (e) {
  console.log(`fetch failed`, e)
}
}

这是我对堆栈溢出的第一个答案。 谢谢!