如何在 JavaScript 中强制程序等待 HTTP 请求完成?

发布于 2024-09-24 04:12:17 字数 173 浏览 2 评论 0原文

JavaScript 有没有办法将 HTTP 请求发送到 HTTP 服务器并等待服务器响应回复?我希望我的程序等待服务器回复,而不是执行此请求之后的任何其他命令。如果HTTP服务器宕机了,我希望在超时后重复HTTP请求,直到服务器回复,然后程序可以继续正常执行。

有什么想法吗?

先感谢您, 萨纳西斯

Is there a way in JavaScript to send an HTTP request to an HTTP server and wait until the server responds with a reply? I want my program to wait until the server replies and not to execute any other command that is after this request. If the HTTP server is down I want the HTTP request to be repeated after a timeout until the server replies, and then the execution of the program can continue normally.

Any ideas?

Thank you in advance,
Thanasis

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

挖个坑埋了你 2024-10-01 04:12:17

编辑:同步请求现在已弃用;您应该始终以异步方式处理 HTTP 请求。

XmlHttpRequestopen() 有第三个参数,旨在表明您想要异步请求(因此通过 onreadystatechange 处理程序处理响应)。

因此,如果您希望它是同步的(即等待答案),只需为第三个参数指定 false 即可。
在这种情况下,您可能还需要为您的请求设置一个有限的timeout属性,因为它会阻止页面直到接收。

这是一个一体化示例函数对于同步和异步:

function httpRequest(address, reqType, asyncProc) {
  var req = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
  if (asyncProc) { 
    req.onreadystatechange = function() { 
      if (this.readyState == 4) {
        asyncProc(this);
      } 
    };
  }
  req.open(reqType, address, !(!asyncProc));
  req.send();
  return req;
}

您可以这样调用:

var req = httpRequest("http://example.com/aPageToTestForExistence.html", "HEAD");  // In this example you don't want to GET the full page contents
alert(req.status == 200 ? "found!" : "failed");  // We didn't provided an async proc so this will be executed after request completion only

EDIT: Synchronous requests are now deprecated; you should always handle HTTP requests in an async way.

There is a 3rd parameter to XmlHttpRequest's open(), which aims to indicate that you want the request to by asynchronous (and so handle the response through an onreadystatechange handler).

So if you want it to be synchronous (i.e. wait for the answer), just specify false for this 3rd argument.
You may also want to set a limited timeout property for your request in this case, as it would block the page until reception.

Here is an all-in-one sample function for both sync and async:

function httpRequest(address, reqType, asyncProc) {
  var req = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
  if (asyncProc) { 
    req.onreadystatechange = function() { 
      if (this.readyState == 4) {
        asyncProc(this);
      } 
    };
  }
  req.open(reqType, address, !(!asyncProc));
  req.send();
  return req;
}

which you could call this way:

var req = httpRequest("http://example.com/aPageToTestForExistence.html", "HEAD");  // In this example you don't want to GET the full page contents
alert(req.status == 200 ? "found!" : "failed");  // We didn't provided an async proc so this will be executed after request completion only
苦行僧 2024-10-01 04:12:17

您可以执行同步请求。 jQuery 示例:

$(function() {
    $.ajax({
       async: false,
       // other parameters
    });
});

您应该查看 jQuery 的 AJAX API。我强烈建议使用像 jQuery 这样的框架来做这些事情。手动执行跨浏览器 ajax 真的很痛苦!

You can perform a synchronous request. jQuery example:

$(function() {
    $.ajax({
       async: false,
       // other parameters
    });
});

You should take a look at jQuery's AJAX API. I highly recommend using a framework like jQuery for this stuff. Manually doing cross-browser ajax is a real pain!

初心未许 2024-10-01 04:12:17

您可以使用 XMLHttpRequest 对象来发送您的请求。发送请求后,您可以检查readyState属性来识别当前状态。 ReadyState 将有以下不同的状态。

  • 未初始化 - 尚未开始加载
  • 正在加载 - 正在加载
  • 交互 - 已加载足够并且用户可以与其交互
  • 完成 - 完全加载

例如:

xmlhttp.open("GET","somepage.xml",true);
xmlhttp.onreadystatechange = checkData;
xmlhttp.send(null);

function checkData()
{
    alert(xmlhttp.readyState);
}

希望这会有所帮助

You can use XMLHttpRequest object to send your request. Once request is sent, you can check readyState property to identify current state. readyState will have following different states.

  • Uninitialized - Has not started loading yet
  • Loading - Is loading
  • Interactive - Has loaded enough and the user can interact with it
  • Complete - Fully loaded

for example:

xmlhttp.open("GET","somepage.xml",true);
xmlhttp.onreadystatechange = checkData;
xmlhttp.send(null);

function checkData()
{
    alert(xmlhttp.readyState);
}

hope this will help

北城孤痞 2024-10-01 04:12:17

对于现代浏览器,我将使用 fetch而不是 XMLHttpRequest。

async function job() {
  const response = await fetch("https://api.ipify.org?format=json", {}) // type: Promise<Response>
  if (!response.ok) {
    throw Error(response.statusText)
  }
  return response.text()
}


async function onCommit() {
  const result = await job()
  // The following will run after the `job` is finished.
  console.log(result)
}

示例

<button onclick="onCommit()">Commit</button>
<script>
  function onCommit() {
    new Promise((resolve, reject) => {
      resolve(job1())
    }).then(job1Result => {
      return job2(job1Result)
    }).then(job2Result => {
      return job3(job2Result)
    }).catch(err => { // If job1, job2, job3, any of them throw the error, then will catch it.
      alert(err)
    })
  }

  async function testFunc(url, options) {
    // options: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
    const response = await fetch(url, options) // type: Promise<Response>
    if (!response.ok) {
      const errMsg = await response.text()
      throw Error(`${response.statusText} (${response.status}) | ${errMsg} `)
    }
    return response
  }

  async function job1() {
    console.log("job1")
    const response =  await testFunc("https://api.ipify.org?format=json", {})
    return await response.json()
  }

  async function job2(job1Data) {
    console.log("job2")
    console.log(job1Data)
    const textHeaders = new Headers()
    textHeaders.append('Content-Type', 'text/plain; charset-utf-8')
    const options = {"headers": textHeaders}
    const response = await testFunc("https://api.ipify.org/?format=text", options)
    // throw Error(`test error`) // You can cancel the comment to trigger the error.
    return await response.text()
  }

  function job3(job2Data) {
    console.log("job3")
    console.log(job2Data)
  }
</script>

For the modern browser, I will use the fetch instead of XMLHttpRequest.

async function job() {
  const response = await fetch("https://api.ipify.org?format=json", {}) // type: Promise<Response>
  if (!response.ok) {
    throw Error(response.statusText)
  }
  return response.text()
}


async function onCommit() {
  const result = await job()
  // The following will run after the `job` is finished.
  console.log(result)
}

an examples

<button onclick="onCommit()">Commit</button>
<script>
  function onCommit() {
    new Promise((resolve, reject) => {
      resolve(job1())
    }).then(job1Result => {
      return job2(job1Result)
    }).then(job2Result => {
      return job3(job2Result)
    }).catch(err => { // If job1, job2, job3, any of them throw the error, then will catch it.
      alert(err)
    })
  }

  async function testFunc(url, options) {
    // options: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
    const response = await fetch(url, options) // type: Promise<Response>
    if (!response.ok) {
      const errMsg = await response.text()
      throw Error(`${response.statusText} (${response.status}) | ${errMsg} `)
    }
    return response
  }

  async function job1() {
    console.log("job1")
    const response =  await testFunc("https://api.ipify.org?format=json", {})
    return await response.json()
  }

  async function job2(job1Data) {
    console.log("job2")
    console.log(job1Data)
    const textHeaders = new Headers()
    textHeaders.append('Content-Type', 'text/plain; charset-utf-8')
    const options = {"headers": textHeaders}
    const response = await testFunc("https://api.ipify.org/?format=text", options)
    // throw Error(`test error`) // You can cancel the comment to trigger the error.
    return await response.text()
  }

  function job3(job2Data) {
    console.log("job3")
    console.log(job2Data)
  }
</script>

你在看孤独的风景 2024-10-01 04:12:17

为此,您可以在页面开始加载时立即在 javascript 中启动加载程序,然后您可以在请求完成或您的 dom 准备就绪时关闭它。
我想说的是,当页面加载开始时,启动加载程序。然后页面可以使用 ajax 进行多个同步请求,直到并且除非您没有得到响应,否则不要关闭 close loader。
在最终调用中收到所需的响应后,您可以关闭加载程序。

For this you can start loader in javascript as soon as page starts loading and then you can close it when request finishes or your dom is ready.
What i am trying to say, as page load starts, start a loader . Then page can do multiple synchronous request using ajax , until and unless you didn't get response, do not close close loader.
After receiving the desired in response in final call, you can close the loader.

北风几吹夏 2024-10-01 04:12:17

我在使用 Three.js 和 Google Closure 构建的游戏中也遇到了类似的情况。我必须加载 2 个资源,三个资源和 Closure 不允许我使这些资源同步。

最初,我天真地写了以下内容:

main() {

  ...
  var loaded=0;
  ...

  // Load Three geometry
  var loader = new THREE.JSONLoader();
  loader.load("x/data.three.json", function(geometry) {
    ...
    loaded++;
    });

   // Load my engine data
  goog.net.XhrIo.send("x/data.engine.json", function(e) {
    var obj = e.target.getResponseJson();
    ...
    loaded++;
    });

  // Wait for callbacks to complete
  while(loaded<2) {}

  // Initiate an animation loop
  ...
};

等待回调完成的循环永远不会结束,从循环 loaded 的角度来看,它永远不会递增。问题是回调在 main 返回之前不会被触发(至少在 Chrome 上)。

一种解决方案可能是让两个回调检查它是否是最后一个完成的,然后它们继续启动动画循环。

另一个解决方案 - 也许是对您所问问题的更直接的答案(如何在启动另一个加载之前等待每个加载) - 是嵌套回调,如下所示:

// Load Three geometry
var loader = new THREE.JSONLoader();
loader.load("x/data.three.json", function(geometry) {
  ...

   // Load my engine data
   goog.net.XhrIo.send("x/data.engine.json", function(e) {
     var obj = e.target.getResponseJson();
     ...

     // Initiate an animation loop
     ...

    });
  });
};

I have a similar situation in an game built with Three.js and Google Closure. I have to load 2 resources, Three and Closure do not allow me to make these synchronous.

Initially I naively wrote the following:

main() {

  ...
  var loaded=0;
  ...

  // Load Three geometry
  var loader = new THREE.JSONLoader();
  loader.load("x/data.three.json", function(geometry) {
    ...
    loaded++;
    });

   // Load my engine data
  goog.net.XhrIo.send("x/data.engine.json", function(e) {
    var obj = e.target.getResponseJson();
    ...
    loaded++;
    });

  // Wait for callbacks to complete
  while(loaded<2) {}

  // Initiate an animation loop
  ...
};

The loop that waits for the callbacks to complete never ends, from the point of view of the loop loaded never get incremented. The problem is that the callbacks are not fired until main returns (at least on Chrome anyway).

One solution might be to have both callbacks check to see if it's the last to complete, and them go on to initiate the animation loop.

Another solution - perhaps a more direct answer to what you are asking (how to wait for each load before initiating another) - would be to nest the callbacks as follows:

// Load Three geometry
var loader = new THREE.JSONLoader();
loader.load("x/data.three.json", function(geometry) {
  ...

   // Load my engine data
   goog.net.XhrIo.send("x/data.engine.json", function(e) {
     var obj = e.target.getResponseJson();
     ...

     // Initiate an animation loop
     ...

    });
  });
};
叹沉浮 2024-10-01 04:12:17

这是一个老问题,但想提供不同的看法。

这是一个异步函数,它创建一个承诺,当请求完成时,该承诺将使用 Http 对象进行解析。这允许您在使用 XMLHttpRequest 时使用更现代的 async/await 语法。

async sendRequest() {
    const Http = new XMLHttpRequest();
    const url='http://localhost:8000/';
    Http.open("GET", url);
    Http.send();

    if (Http.readyState === XMLHttpRequest.DONE) {
        return Http;
    }

    let res;
    const p = new Promise((r) => res = r);
    Http.onreadystatechange = () => {
        if (Http.readyState === XMLHttpRequest.DONE) {
            res(Http);
        }
    }
    return p;
}

用法

const response = await sendRequest();
const status = response.status;
if (status === 0 || (status >= 200 && status < 400)) {
    // The request has been completed successfully
    console.log(response.responseText);
} else {
    // Oh no! There has been an error with the request!
    console.log(`Server Error: ${response.status}`)
}

This is an old question but wanted to provide a different take.

This is an async function that creates a promise that resolves with the Http object when the request is complete. This allow you to use more modern async/await syntax when working with XMLHttpRequest.

async sendRequest() {
    const Http = new XMLHttpRequest();
    const url='http://localhost:8000/';
    Http.open("GET", url);
    Http.send();

    if (Http.readyState === XMLHttpRequest.DONE) {
        return Http;
    }

    let res;
    const p = new Promise((r) => res = r);
    Http.onreadystatechange = () => {
        if (Http.readyState === XMLHttpRequest.DONE) {
            res(Http);
        }
    }
    return p;
}

Usage

const response = await sendRequest();
const status = response.status;
if (status === 0 || (status >= 200 && status < 400)) {
    // The request has been completed successfully
    console.log(response.responseText);
} else {
    // Oh no! There has been an error with the request!
    console.log(`Server Error: ${response.status}`)
}
×眷恋的温暖 2024-10-01 04:12:17

对于使用 axios 的用户,您可以将其包装在 async iife 中,然后await it:

(async () => {
  let res = await axios.get('https://example.com');

  // do stuff with the response
})();

注意,我在这里没有进行任何错误检查。

For those using axios, you can wrap it in an async iife and then await it:

(async () => {
  let res = await axios.get('https://example.com');

  // do stuff with the response
})();

Note, I haven't done any error checking here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文