【问题标题】:Aborting previous XMLHttpRequest中止先前的 XMLHttpRequest
【发布时间】:2015-02-09 04:35:45
【问题描述】:

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

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?

【问题讨论】:

  • 只调用它的abort() 方法?
  • Aborting the xmlhttprequest 的可能重复项
  • 与其放弃,为什么不先发送请求,直到用户停止输入?
  • @KevinB 我希望它是实时搜索!
  • @Bergi 我在哪里使用它?

标签: javascript xmlhttprequest


【解决方案1】:

如果您仍然要中止请求,则最好在检测到用户仍在键入时首先阻止发送请求。

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);
}

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

这与使用中止相同,除了服务器不会被您无论如何都会中止的 ajax 请求轰炸,并且请求中增加了 150 毫秒的延迟。

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

使用该插件,您可以让它在每个 timer 毫秒内发送不超过 1 个请求,从而导致第一个密钥始终发送请求,而另一个密钥直到 timer 毫秒过去后才发送,从而为您提供更多实时查看结果。

【讨论】:

    【解决方案2】:

    在这里,我将分享一些关于我在我的 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来处理promise/reject,根据你的代码你可以处理你自己的promise/reject 代码:

    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)
    }
    }
    

    这是我在 Stack Overflow 上的第一个答案。 谢谢!!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      • 2010-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多