Abstract

This article introduces three asynchronous network request writing methods based on XMLHttpRequest, Promise and async/await. The async/await writing method allows us to write asynchronous programs in a synchronous manner and get rid of the tedious callback functions.

The background,

In order to cope with more and more test requirements and reduce repetitive work, Youdao Intelligent hardware test group developed a series of test efficiency improvement tools based on ELECTRON.

The programming language of ELECTRON is JS. Since everyone is not a professional front-end, they are not familiar with JS, so they have made a lot of mistakes when writing programs. In particular, events and network requests in JS, where asynchronous programming is involved, are prone to errors.

With the rapid development of the tool, more and more nested callback functions appear in the code, and the chance of the tool crashing increases. To solve these problems, we refactor these callback functions with async/await, which reduces the code volume and greatly improves the readability and understandability of the code.

This article introduces three asynchronous network request writing methods based on XMLHttpRequest, Promise and async/await. The async/await writing method allows us to write asynchronous programs in a synchronous manner and get rid of the tedious callback functions.

Second, the preface

Simply making a single web request in JS is not too complicated; fetch, AXIos, or XMLHttpRequest will suffice.

If multiple requests pull data sequentially, it can be difficult to write 😂, because network requests in JS are asynchronous. The most common way to write sequential requests is to make the next request in the callback function, as shown in the following code:

const requestOptions = {
    method: 'GET'.redirect: 'follow'
};

fetch('https://xxx.yyy.com/api/zzz/', requestOptions)
    .then(response= > response.json())
    .then(data= > {
        fetch('https://xxx.yyy.com/api/aaa/'+data.id, requestOptions)
            .then(response= > response.json())
            .then(data= > {
                console.log(data)
            })
            .catch(error= > console.error('error', error));
    })
    .catch(error= > console.error('error', error));
Copy the code

Suppose I need to get a piece of data in two steps, such as from *xxx.yyy.com/api/zzz*/…

The callback method is similar to the above method, which is too cumbersome, error-prone, and difficult to change once the logic is complex.

Next sort out several js network request way, get rid of callback hell, hope to meet similar problems of small partners help.

(a) the XMLHttpRequest

The first one is XMLHttpRequest, which is what Ajax was all about when you first learned about the front end. Here’s how to create a web request from an XMLHttpRequest object:

Visit http://localhost:3000/user / / assume that returns a json object {" name ":" YouDao "}
const xhr = new XMLHttpRequest();
const url = 'http://localhost:3000/user'

xhr.onreadystatechange = function(){
  if (this.readyState == 4 && this.status == 200) {const json=JSON.parse(xhr.responseText)
    const name=json.name
    console.log(name)
  }
}
xhr.open('GET',url)
xhr.send()
Copy the code

This code first creates an XMLHttpRequest object XHR, then adds a callback to the readyStatechange event to xhr.onReadyStatechange, after which xhr.open(‘GET’, URL) initializes the request, Finally, xhr.send() sends the request.

After the request is sent, the program continues to execute without blocking, which is another benefit of asynchronous calls. When the browser receives the response, it goes to the xhr. onreadyStatechange callback function. Xhr.onreadystatechange triggers four times throughout the request, and each time the readyState increases from 1 to 4, the final response data is returned only at the last stage, when the readyState is 4. After reaching the fourth stage, the status code of the response should be judged according to the status. Usually, the response code is 200, indicating that the request has no problems. This code will eventually type YouDao on the console.

As you can see, to handle requests with XMLHttpRequest, you need to first create an XMLHttpRequest object for each request, and then bind the readyStatechange event callback function to each object, which can be quite cumbersome if multiple requests are strung together.

(2) the Promise

Promise was introduced in ECMAScript 2015, and using callbacks can complicate code if one event depends on the result returned by another event. The Promise object provides a mode for checking for the failure or success of an operation. If successful, another Promise is returned. This makes the writing of callbacks more formal.

Here’s what happens with Promise:

const promise = new Promise((resolve,reject) = >{
  let condition = true;
  if (condition) {
    resolve("ok")}else {
    reject("failed")
  }
}).then( msg= > console.log(msg))
  .catch( err= > console.error(err))
  .finally( _= >console.log("finally"))

Copy the code

The above code strings the process together by creating a Promise object whose constructor takes a function whose first argument is resolve, which is to be executed if nothing goes wrong, and its second argument is reject, which is to be executed if anything goes wrong.

Resolve is the callback in THEN after a successful execution, reject is the callback in catch after a failed execution. The finally is executed regardless of success or failure and can be used to do some cleaning up.

Promise-based web requests can be implemented using the AXIos library or the browser’s own FETCH.

The axios library creates requests as follows:

import axios from 'axios'
const url = 'http://xxx.yyy.com/'
axios.get(url)
  .then(data= > console.log(data))
  .catch(err= > console.error(err))
Copy the code

Fetch is a browser API that replaces XMLHttpRequest. It doesn’t require a library guide. Fetch creates requests in a similar way to AXIOS.

Promise simplifies the way callback functions are written, but it doesn’t get rid of callback hell, where multiple requests can be strung together to create new promises inside then, as I wrote at the beginning, and eventually Promise hell.

(3) the async/await

Async /await was introduced in ECMAScript 2017 to simplify Promise writing so that asynchronous function calls in code can be executed sequentially and easily understood.

Here’s an example from the beginning:

Fetch data directly:

const requestOptions = {
    method: 'GET'.redirect: 'follow'
};

fetch('https://xxx.yyy.com/api/zzz/', requestOptions)
    .then(response= > response.json())
    .then(data= > {
        fetch('https://xxx.yyy.com/api/aaa/'+data.id, requestOptions)
            .then(response= > response.json())
            .then(data= > {
                console.log(data)
            })
            .catch(error= > console.error('error', error));
    })
    .catch(error= > console.error('error', error));
Copy the code

With async/await:

async function demo() {
​  const requestOptions = {
    method: 'GET'.redirect: 'follow'
  };

  const response = await fetch('https://xxx.yyy.com/api/zzz/', requestOptions);
  const data = await response.json()
  const response1 = await fetch('https://xxx.yyy.com/api/aaa/'+data.id, requestOptions)
  const data1 = await response1.json()
  console.log(data1)
}

demo().catch(error= > console.error('error',error))
Copy the code

The rewritten code makes it clear that there are not so many “THEN” s that follow, so there is no need to worry if there are a series of network requests.

When async precedes the declaration of a function, the function is an asynchronous function, and calling the function returns a Promise. Await is used to wait for a Promise object. It can only be used in asynchronous functions, and await expression suspends the execution of the current asynchronous function until the Promise processing completes.

So if you want a series of asynchronous function calls to be executed sequentially, just put the called functions in an async modified function with await before the call and the functions will be executed sequentially.

conclusion

Through this article, you’ve figured out how to avoid callback hell. Note that Promise was added to the specification in 2015, while async/await was only added in 2017. If your project is older or you have to be compatible with older browsers (IE6😂), then there are other ways to get around callback hell. As for Electron, as long as you’re using a recent version and it’s supported, Electron can be used as a chromium/Node.js hybrid, making it ideal for writing cross-platform tool-like desktop applications.