当数据已经到达第一个响应时,消除发送 Xmlhttprequest 的开销

Posted

技术标签:

【中文标题】当数据已经到达第一个响应时,消除发送 Xmlhttprequest 的开销【英文标题】:Removing the Overhead of sending Xmlhttprequest when the the data already arrived in the first response 【发布时间】:2020-09-19 14:17:09 【问题描述】:

我正在构建一个随机报价生成器,为此我使用 Xmlhttprequest 从 API 获取报价。 当有人单击“生成报价”按钮时,会向 Api 发送一个 http 获取请求,并且每次单击都会显示随机报价。一切对我来说都很好,但唯一的问题是每次点击我都会发送一个新的 http 请求,我想发送一次请求,然后继续显示响应数据。我在这里尝试过使用 abort() 方法,但我仍然面临一些问题。 谁能指导我如何实现它?

MY html files looks something like this
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="assets/styles/app.css"> 
    <script src="assets/scripts/xmlhttprequest.js" defer></script>
    <!-- <script src="assets/scripts/app.js"></script> -->

</head>
<body>
    <div id="main">
        <h2 id="heading">Random Quotes Generator</h2>
        <div id="quotes">
            <button class="btn btn-primary btn-lg">Generate Quotes</button>
            </div>
            <div>
               <article></article>
               <p id="authorName"></p>
    </div>
    
        
        
    </div>
</body>
</html>


CSS code

body

    background-color:darkcyan;


#heading

    font-style: oblique;
    display: flex;
    justify-content: center;
    margin-left: 60px;
   margin-top: 30px;
    

#quotes

    margin-left: 45%;
    margin-top: 50px;
    
    

.inner
    background-color:lightblue;
    border: 0px solid green;
    border-style:groove;
    padding:90px; /*--100*/
    margin-left: 30%;
    margin-top: 50px;
    margin-bottom:20px;
    width:40%;
    font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    font-weight:600;
    font-size: 20px;
    color:saddlebrown;


#authorName
    text-align:right;
    color: lightseagreen;



javascript code -
const button=document.querySelector('button')
const innerQuotesDiv=document.querySelectorAll('div')[2]
const article=innerQuotesDiv.firstElementChild
const authorName=article.nextElementSibling
    
function generateRandomIndex(length)

    console.log(length)
    return (Math.floor(Math.random()*length))
  

  function getQuotes()
    
   // console.log(noOfTimesBtnClicked)
    let xhr=new XMLHttpRequest()
    xhr.open('GET','https://type.fit/api/quotes')
    xhr.onload=function()

      let quotes=JSON.parse(xhr.response)
        console.log(quotes)
        let index=generateRandomIndex(quotes.length)
        innerQuotesDiv.classList.add('inner')
        article.textContent=quotes[index].text 
        if(!quotes[index].author)
       
           authorName.textContent='Anonymous'  
       
       else
        authorName.textContent=quotes[index].author  
       
    
    
    xhr.onerror=function()

      console.log(xhr.response)
      console.log(xhr.status)
      alert('something went wrong')
  
  xhr.send() 
  
  

  function abortGetRequest(xhr)
    
    xhr.abort()
  



  button.addEventListener('click',()=>

    //console.log('clicked')
    


    getQuotes()

    

)


JS code in which i have tried to use abort() --


const button=document.querySelector('button')
const innerQuotesDiv=document.querySelectorAll('div')[2]
const article=innerQuotesDiv.firstElementChild
const authorName=article.nextElementSibling


function generateRandomIndex(length)

    console.log(length)
    return (Math.floor(Math.random()*length))
  

  function getQuotes()
    
   // console.log(noOfTimesBtnClicked)
    let xhr=new XMLHttpRequest()
    xhr.open('GET','https://type.fit/api/quotes')
    xhr.onload=function()

      let quotes=JSON.parse(xhr.response)
        console.log(quotes)
        let index=generateRandomIndex(quotes.length)
        innerQuotesDiv.classList.add('inner')
        article.textContent=quotes[index].text 
        if(!quotes[index].author)
       
           authorName.textContent='Anonymous'  
       
       else
        authorName.textContent=quotes[index].author  
       
    
    
    xhr.onerror=function()

      console.log(xhr.response)
      console.log(xhr.status)
      alert('something went wrong')
  
  xhr.send() 
  abortGetRequest(xhr)

  

  function abortGetRequest(xhr)
    
    xhr.abort()
  

function displayQuotes(quotes)

  let index=generateRandomIndex(quotes.length)
  innerQuotesDiv.classList.add('inner')
  article.textContent=quotes[index].text 
  if(!quotes[index].author)
 
     authorName.textContent='Anonymous'  
 
 else
  authorName.textContent=quotes[index].author  
 



  button.addEventListener('click',()=>

    //console.log('clicked')
    


    getQuotes()

   
    

)

使用 fetch API - 我在引号中变得未定义我认为这是因为引号在 onload 函数之前执行。我怎么能同步或有任何其他方式可以使用来自分配给报价变量的承诺的数据。

const button=document.querySelector('button')
const innerQuotesDiv=document.querySelectorAll('div')[2]
const article=innerQuotesDiv.firstElementChild
const authorName=article.nextElementSibling
let quotes;
// console.log(button)
// console.dir(innerQuotesDiv)
 //console.log(article)
 //console.log(authorName)

 quotes=window.addEventListener('load',fetchApi)
function generateRandomIndex(length)

  console.log(length)
  return (Math.floor(Math.random()*length))


function fetchApi()

   let d=fetch('https://type.fit/api/quotes')
    .then(response=>
        return response.json()
    )
    .then(data=>
        console.log(data)
        return data
    )
    console.log(d)
    return d





function changeQuotes()
     
    console.log(quotes)
    let index=generateRandomIndex(quotes.length)
    innerQuotesDiv.classList.add('inner')
    article.textContent=quotes[index].text 
    if(!quotes[index].author)
   
       authorName.textContent='Anonymous'  
   
   else
    authorName.textContent=quotes[index].author  
   


  button.addEventListener('click',()=>
      
         changeQuotes()
  )

【问题讨论】:

那些“一些问题”是什么? What Do You Mean “It Doesn’t Work”? 见Why is “Can someone help me?” not an actual question?。为什么单击按钮会获取引号?为什么不简单地在页面加载时获取它们一次? 问题是根本没有结果,或者在再次单击按钮后只显示一个报价没有任何反应。我将尝试在页面加载时获取它。 嗨,我已经在加载时完成了它,它工作正常。我如何使用 fetch api 来做到这一点?我也包含了 fetch api 代码。我不知道如何使用 fetch api 来做到这一点。你可以看到 fetch api 的代码。 【参考方案1】:

我没有测试这个,但是...

window.addEventListener('DOMContentLoaded', ()=>
    const innerQuotesDiv=document.querySelectorAll('div')[2]
    const article=innerQuotesDiv.firstElementChild
    const authorName=article.nextElementSibling

    function changeQuotes(quotes) 
        console.log(quotes)
        let index = generateRandomIndex(quotes.length)
        innerQuotesDiv.classList.add('inner')
        article.textContent = quotes[index].text
        if (!quotes[index].author) 
            authorName.textContent = 'Anonymous'
         else 
            authorName.textContent = quotes[index].author
        
    

    const request= fetchData('https://type.fit/api/quotes');

    document.querySelector('button').addEventListener('click',()=>
           request.then(changeQuotes);
    )
)

function generateRandomIndex(length)
    console.log(length)
    return (Math.floor(Math.random()*length))


function fetchData(url) 
    return fetch(url)
        .then(response => 
            return response.json()
        )
        .then(data => 
            console.log(data)
            return data
        )

【讨论】:

但是你能解释一下这段代码是如何工作的吗 document.querySelector('button').addEventListener('click',()=> request.then(changeQuotes); ) 我们只是发出一个请求,当按钮被点击时,我们添加一个带有 changeQuotes 处理程序的新then 链到请求承诺,如果请求承诺已经被处理,则可以立即调用请求的数据,或者稍后在请求准备好时。这个表达式是 request.then ((quotes) => changeQuotes (quotes));的简写;

以上是关于当数据已经到达第一个响应时,消除发送 Xmlhttprequest 的开销的主要内容,如果未能解决你的问题,请参考以下文章

C# HTTPClient 不发送请求

初始TCP协议

与 DB 和 URL 交互的并发处理

工程师基本常识

发送消息超时,咋办

QTcpSocket的连续发送数据和连续接收数据