preface

The async functions and await keywords were recently added to the JavaScript language. They are part of ECMAScript 2017 JavaScript edition. In simple terms, they are based on Promises syntectic candy that makes asynchronous code easier to write and read. Using them, asynchronous code looks more like old-fashioned synchronous code, so they’re well worth learning.

Async/await the foundation

There are two parts to using async/await in code.

1. Async keyword

First, we use the async keyword and place it before the function declaration to make it async Function. An asynchronous function is a function that knows how to call asynchronous code using the await keyword.

Try typing the following line in your browser’s JS console:

function hello() { return "Hello" };
hello();
Copy the code

This function returns “Hello” — nothing special, right?

What if we make it an asynchronous function? Try the following:

async function hello() { return "Hello" };
hello();
Copy the code

Ha. Calling this function now returns a promise. This is one of the characteristics of asynchronous functions — it guarantees that the function returns a promise.

You can also create async function expression as follows:

let hello = async function() { return "Hello" };
hello();
Copy the code

You can use the arrow function:

let hello = async() = > {return "Hello" };
Copy the code

These are all basically the same.

To actually use the value returned when a promise completes, we can use the.then() block, since it returns a promise:

hello().then((value) = > console.log(value))
Copy the code

Or even just shorthand

hello().then(console.log)
Copy the code

Adding the async keyword to a function declaration tells them to return a promise instead of returning a value directly. Furthermore, it avoids any potential overhead of synchronization functions to support the use of await. When a function is declared async, the JavaScript engine adds the necessary processing to optimize your program. Cool!

2. Await keyword

  • The real advantage of the await keyword becomes apparent when it is used with asynchronous functions – in fact, await only works within asynchronous functions.

  • awaitThe keyword can precede any asynchronous, promise-based function. It pauses the code on that line until the promise completes, then returns the result value. At the same time as the pause, other code waiting to be executed has a chance to execute.

  • You can use await when calling any function that returns a Promise, including Web API functions.

Here is a simple example 🌰 :

async function hello() {
  return greeting = await Promise.resolve("Hello");
};

hello().then(alert);
Copy the code

Of course, the above example isn’t very useful, but it does show the syntax. Let’s move on and look at a real-world example.

Rewrite the Promise code with async/await

Let’s look at a simple fetch example:

fetch('coffee.jpg')
.then(response= > response.blob())
.then(myBlob= > {
  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch(e= > {
  console.log(e.message);
});
Copy the code

By now, you should have a good understanding of Promises and how they work. Let’s convert this to using async/await and see how much easier it makes things:

async function myFetch() {
  let response = await fetch('coffee.jpg');
  let myBlob = await response.blob();

  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
}

myFetch()
.catch(e= > {
  console.log(e.message);
});
Copy the code

It makes the code much simpler and easier to understand — removing.then() blocks that are everywhere!

Since the async keyword converts a function to a promise, you can refactor the above code — extracting the second half of the function into a new block using a mixture of promise and await. Doing so can be more flexible:

async function myFetch() {
  let response = await fetch('coffee.jpg');
  return await response.blob();
}

myFetch().then((blob) = > {
  let objectURL = URL.createObjectURL(blob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
});
Copy the code

1. How does it work

You’ll notice that we’ve wrapped the code in functions, and we’ve included the async keyword before the function keyword. This is necessary — you must create an asynchronous function to define a block of code in which to run asynchronous code; Await can only work inside asynchronous functions.

In the myFetch() function definition, you can see that the code is very similar to the previous promise version, with some differences. Instead of appending.then() blocks to the end of each promise-based method, you just add the await keyword before the method call and assign the result to the variable. The await keyword suspends the JavaScript runtime on this line, allowing other code to execute in the meantime until the asynchronous function call returns its result. Once done, your code will proceed from the next line. Such as:

let response = await fetch('coffee.jpg');
Copy the code

The parser pauses on this line until the response returned by the server becomes available. At this point, the promise returned by fetch() will be filled, and the response returned will be assigned to the response variable. Once the response returned by the server is available, the parser moves to the next line, creating a Blob (we’ll see what that blog is later). The Blob line also calls asynchronous promise-based methods, so we use await here as well. When the result of the operation returns, we return it from myFetch().

This means that when we call myFetch(), it returns a promise, so we can link.then() to the end of it, where we process the blob displayed on the screen.

You may already be thinking, “This is really cool!” You’re right — encapsulate the code with fewer.then() blocks, and it looks a lot like synchronous code, so it’s pretty intuitive.

◾ ️ Blob

A Blob object represents an immutable, raw data-like file object. Its data can be read in text or binary format, or converted to ReadableStream for data manipulation.

Blobs don’t necessarily represent data in JavaScript’s native format. The File interface is based on Blob, inheriting the functionality of Blob and extending it to support files on the user’s system.

To construct a BLOb from other non-BLOb objects and data, use the blob () constructor. To create a subset bloB of bloB data, use the slice() method. To get the Blob object corresponding to the File on the user’s File system, see the File document.

The apis that accept Blob objects are also listed in the File document.

2. Add error handling

If you want to add error handling, you have several options.

You can synchronize the try… The catch construct is used with async/await. This example extends the first version of the code we showed above:

async function myFetch() {
  try {
    let response = await fetch('coffee.jpg');
    let myBlob = await response.blob();

    let objectURL = URL.createObjectURL(myBlob);
    let image = document.createElement('img');
    image.src = objectURL;
    document.body.appendChild(image);
  } catch(e) {
    console.log(e);
  }
}

myFetch();
Copy the code

The catch() {} block receives an error object e; We can now log this to the console, which will give us a detailed error message showing where in the code the error was thrown.

If you want to use the second (refactoring) version of the code we showed above, you’re better off continuing to mix methods and link the.catch() block to the end of the.then() call, like this:

async function myFetch() {
  let response = await fetch('coffee.jpg');
  return await response.blob();
}

myFetch().then((blob) = > {
  let objectURL = URL.createObjectURL(blob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch((e) = >
  console.log(e)
);
Copy the code

This is because the.catch() block catches errors from asynchronous function calls and the promise chain. If you use a try/catch block here, you may still get an unhandled error when you call myFetch().

Wait for the Promise. All ()

Async/await is built on Promises, so it is compatible with everything Promises offers. This includes promise.all () — you can completely return all results to variables by calling await promise.all (), just like synchronizing code.

async function fetchAndDecode(url, type) {
  let response = await fetch(url);

  let content;

  if(type === 'blob') {
    content = await response.blob();
  } else if(type === 'text') {
    content = await response.text();
  }

  return content;
}

async function displayContent() {
  let coffee = fetchAndDecode('coffee.jpg'.'blob');
  let tea = fetchAndDecode('tea.jpg'.'blob');
  let description = fetchAndDecode('description.txt'.'text');

  let values = await Promise.all([coffee, tea, description]);

  let objectURL1 = URL.createObjectURL(values[0]);
  let objectURL2 = URL.createObjectURL(values[1]);
  let descText = values[2];

  let image1 = document.createElement('img');
  let image2 = document.createElement('img');
  image1.src = objectURL1;
  image2.src = objectURL2;
  document.body.appendChild(image1);
  document.body.appendChild(image2);

  let para = document.createElement('p');
  para.textContent = descText;
  document.body.appendChild(para);
}

displayContent()
.catch((e) = >
  console.log(e)
);
Copy the code

Look at promise.all () line:

let values = await Promise.all([coffee, tea, description]);
Copy the code

Here, by using await, we can put the results of all three promises into the values array when they are available. This looks a lot like synchronous code. We need to wrap all the code in a new asynchronous function displayContent(), which, while not much less, moves most of the code out of the.then() block, making the code simpler and more readable.

For error handling, we include a.catch() block in the displayContent() call; This will handle errors in both functions.

Note: It is also possible to replace the.finally() asynchronous code block with a synchronous finally block in an asynchronous function to show the final report of how the operation proceeded.

Defects and solutions of async/await

Knowing Async/await is very useful, but there are some disadvantages to consider.

  • Async/awaitMake your code look synchronous and, to some extent, make it behave more synchronous. The await keyword blocks subsequent code until the promise completes, as if a synchronization operation had been performed. It does allow other tasks to continue running in the meantime, but your own code is blocked.

  • This means that your code could be compromised by a large number ofawaitPromises happen one after another. Each await will be waiting for the previous one to finish, and what you really want is for all these promises to start processing at the same time (as if we didn’t use them)async/awaitAs).

One pattern alleviates this problem — start Promise objects simultaneously by storing them in variables, and then wait for them all to complete. Let’s look at some examples to prove this concept.

We have two examples available — slow-async-await.html and fast-async-await.html.

◾ ️ missile async/await

<! DOCTYPE html><html>
  <head>
    <meta charset="utf-8">
    <title>Demonstration of slow async/await</title>
  </head>
  <body>
    <script>
      // Define custom promise function

      function timeoutPromise(interval) {
        return new Promise((resolve, reject) = > {
          setTimeout(function(){
            resolve("done");
          }, interval);
        });
      };

      async function timeTest() {
        await timeoutPromise(3000);
        await timeoutPromise(3000);
        await timeoutPromise(3000);
      }

      let startTime = Date.now();
      timeTest().then(() = > {
        let finishTime = Date.now();
        let timeTaken = finishTime - startTime;
        alert("Time taken in milliseconds: " + timeTaken);
      })
    </script>
  </body>
</html>
Copy the code

◾ ️ fast async/await

<! DOCTYPE html><html>
  <head>
    <meta charset="utf-8">
    <title>Demonstration of fast async/await</title>
  </head>
  <body>
    <script>
      // Define custom promise function

      function timeoutPromise(interval) {
        return new Promise((resolve, reject) = > {
          setTimeout(function(){
            resolve("done");
          }, interval);
        });
      };

      async function timeTest() {
        const timeoutPromise1 = timeoutPromise(3000);
        const timeoutPromise2 = timeoutPromise(3000);
        const timeoutPromise3 = timeoutPromise(3000);

        await timeoutPromise1;
        await timeoutPromise2;
        await timeoutPromise3;
      }

      let startTime = Date.now();
      timeTest().then(() = > {
        let finishTime = Date.now();
        let timeTaken = finishTime - startTime;
        alert("Time taken in milliseconds: " + timeTaken);
      })
    </script>
  </body>
</html>
Copy the code

They all start with a custom promise function that calls the bogus asynchronous process using setTimeout() :

function timeoutPromise(interval) {
  return new Promise((resolve, reject) = > {
    setTimeout(function(){
      resolve("done");
    }, interval);
  });
};
Copy the code

Then each contains a timeTest() asynchronous function waiting for three timeoutPromise() calls:

async function timeTest() {... }Copy the code

Each one ends with a record start time, look at how long it will take a timeTest() promise to complete, then record the end time and report how long the operation will take in total:

let startTime = Date.now();
timeTest().then(() = > {
  let finishTime = Date.now();
  let timeTaken = finishTime - startTime;
  alert("Time taken in milliseconds: " + timeTaken);
})
Copy the code

The timeTest() function is different in each case.

◾️ In the slow-async-await.html example, timeTest() looks like this:

async function timeTest() {
  await timeoutPromise(3000);
  await timeoutPromise(3000);
  await timeoutPromise(3000);
}
Copy the code

Here, we simply wait for all three timeoutPromise () calls, making each call 3 seconds. Each subsequent one is forced to wait until the last one is completed – if you run the first example, you’ll see pop-ups reporting a total running time of about 9 seconds.

◾️ In the fast-async-await.html example, timeTest() looks like this:

async function timeTest() {
  const timeoutPromise1 = timeoutPromise(3000);
  const timeoutPromise2 = timeoutPromise(3000);
  const timeoutPromise3 = timeoutPromise(3000);

  await timeoutPromise1;
  await timeoutPromise2;
  await timeoutPromise3;
}
Copy the code

Here, we store the three Promise objects in variables that can start their associated processes at the same time.

Next, we wait for their results – since promises are all started at roughly the same time, promises will be fulfilled at the same time; When you run the second example, you’ll see pop-ups reporting a total elapsed time of just over 3 seconds!

You must test your code carefully and keep this in mind when performance starts to suffer.

Another minor inconvenience is that you must encapsulate promises waiting to be executed in asynchronous functions.

Class method of Async/await

Finally, it is worth mentioning that we can add async in front of class/object methods to make them return Promises and await promises inside them.

class Person {
  constructor(first, last, age, gender, interests) {
    this.name = {
      first,
      last
    };
    this.age = age;
    this.gender = gender;
    this.interests = interests;
  }

  async greeting() {
    return await Promise.resolve(`Hi! I'm The ${this.name.first}`);
  };

  farewell() {
    console.log(`The ${this.name.first}has left the building. Bye for now! `);
  };
}

let han = new Person('Han'.'Solo'.25.'male'['Smuggling']);
Copy the code

The first example method can be used as follows:

han.greeting().then(console.log);
Copy the code

Browser support

One consideration when deciding whether to use async/await is support for older browsers. They work with modern versions of most browsers, the same as Promise; The main support issues are with Internet Explorer and Opera Mini.

If you want to use async/await but are worried about old browser support, you can consider using the BabelJS library — this allows you to write applications using the latest JavaScript and let Babel figure out what changes the user’s browser needs. When encountering a browser that does not support async/await, Babel’s Polyfill can automatically provide an implementation suitable for older browsers.

The statement

This article is reprinted from: developer.mozilla.org/en-US/docs/…

Words, nuggets hair article is not set to reprint it, did not find a place to set 😅

conclusion

Async /await provides a nice, simplified way to write asynchronous code that is easier to read and maintain. Even though browser support was more limited than other asynchronous code mechanisms at the time of this writing, it is worth learning about and considering using now and in the future.

❤ ️ end

If this article is helpful to your study, please like it 👍, collect it ⭐ and leave a comment 📝. Your support is my motivation to create and share!

If you have any questions during the learning process,Click here to, you can get my contact information and communicate with me ~

Pay attention to the public account “front-end yuan Yuan”, the first time to get updates.

More full more detailed quality content, click here to view