How to force a program to wait until an HTTP request is finished in JavaScript?

Viewed 127837

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

8 Answers

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>

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

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.

Related