Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to simplify Asynchronous Code with Async function

2025-04-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Today, I will talk to you about how to use the Async function to simplify asynchronous code, which may not be well understood by many people. In order to make you understand better, the editor has summarized the following content for you. I hope you can get something according to this article.

Promise became popular on the Internet when it was released on JavaScript. They helped developers get rid of the callback hell and solved the asynchronous problem that plagued JavaScript developers in many places.

With the advent of ES6 (now known as ES2015), in addition to introducing the specification of Promise without requiring countless libraries, we have generators. The generator can stop execution inside the function, which means that they can be encapsulated in a multi-purpose function, and we can wait for the asynchronous operation to complete before the code moves to the next line. Suddenly your asynchronous code may start to look synchronized.

This is only the first step. Asynchronous functions have been standardized since joining ES2017 this year, and local support has been further optimized. The idea of asynchronous functions is to use generators for asynchronous programming and give their own semantics and syntax. Therefore, you do not need to use the library to get encapsulated utility functions, because these will be processed in the background.

To run the async/await instance in the article, you need a compatible browser.

Run compatible

On the client side, Chrome, Firefox, and Opera support asynchronous functions well.

Starting with version 7.6, Node.js enables async/await by default.

Comparison between asynchronous function and generator

Here is an example of asynchronous programming using a generator, using the Q library:

Var doAsyncOp = Q.async (function* () {var val = yield asynchronousOperation (); console.log (val); return val;})

Q.async is a wrapper function that handles things after the scene. Where * represents the function as a generator function, and yield represents the stop function and replaces it with the encapsulated function. Q.async will return a function that you can assign to it, just like doAsyncOp, and then call it.

The new syntax in ES7 is more concise. Examples are as follows:

Async function doAsyncOp () {var val = await asynchronousOperation (); console.log (val); return val;}

There is not much difference. We removed an encapsulated function and * symbol and replaced it with the async keyword instead. The yield keyword is also replaced by await. The two examples actually do the same thing: after the asynchronousOperation is complete, assign a value to val, then output it and return the result.

Convert Promises to an asynchronous function

What would the previous example look like if we used Vanilla Promises?

Function doAsyncOp () {return asynchronousOperation () .then (function (val) {console.log (val); return val;});}

There are the same number of lines of code here, but this is because then and the callback function passed to it add a lot of extra code. Another annoying thing is the two return keywords. Something has been bothering me because it's hard to figure out exactly what the function that uses promises returns.

As you can see, this function returns a promises that will be assigned to val. Guess what the generator and asynchronous function examples have done! No matter what you return in this function, you are actually secretly returning a promise to parse to that value. If you don't return any value at all, the promise you secretly return is parsed to undefined.

Chain operation

One of the reasons why Promise is so popular is that it can connect multiple asynchronous operations in a chained way, avoiding embedded callbacks. But the async function is even better than Promise in this respect.

The following demonstrates how to use Promise for chained operations (we simply run asynchronousOperation multiple times to demonstrate).

Function doAsyncOp () {return asynchronousOperation () .then (function (val) {return asynchronousOperation (val);}) .then (function (val) {return asynchronousOperation (val);}) .then (function (val) {return asynchronousOperation (val);});}

With the async function, you only need to call asynchronousOperation as you would write synchronization code:

Async function doAsyncOp () {var val = await asynchronousOperation (); val = await asynchronousOperation (val); val = await asynchronousOperation (val); return await asynchronousOperation (val);}

Even the return statement of * does not need to use await, because with or without, it returns a Promise that contains the final value that can be processed.

Concurrent operation

Another great feature of Promise is that they can perform multiple asynchronous operations at the same time until they are all done before moving on to other events. Promise.all () is provided in the ES2015 specification, which is used to do this.

Here is an example:

Function doAsyncOp () {return Promise.all ([asynchronousOperation (), asynchronousOperation ()]) .then (function (vals) {vals.forEach (console.log); return vals;});}

Promise.all () can also be used as an async function:

Async function doAsyncOp () {var vals = await Promise.all ([asynchronousOperation (), asynchronousOperation ()]); vals.forEach (console.log.bind (console)); return vals;}

Even with Promise.all, the code is still clear.

Deal with rejection

Promises can be accepted (resovled) or rejected (rejected). The rejected Promise can be handled by a function that is passed to then as its second argument, or to the catch method. Now that we are not using the methods in Promise API, what should we do with rejections? It can be handled by try and catch. When using the async function, rejections are passed as errors so that they can be handled through the error handling code supported by JavaScript itself.

Function doAsyncOp () {return asynchronousOperation () .then (function (val) {return asynchronousOperation (val);}) .then (function (val) {return asynchronousOperation (val);}) .catch (function (err) {console.error (err);});}

This is very similar to our example of chained processing, except that its * link is changed to call catch. If you write with the async function, it will look like this.

Async function doAsyncOp () {try {var val = await asynchronousOperation (); val = await asynchronousOperation (val); return await asynchronousOperation (val);} catch (err) {console.err (err);}}

It's not as simple as other conversions to async functions, but it's exactly the same as writing synchronization code. If you don't catch the error here, it will be thrown up the call chain until it is caught somewhere. If it is never caught, it will eventually abort the program and throw a run-time error. Promise works the same way, except that it refuses to be treated as an error; they may just be a string that describes the error condition. If you do not catch rejections created as errors, you will see a run-time error, but if you just use a string, you will fail without output.

Interrupt Promise

To reject the native Promise, you just need to use Promise to build the reject in the function, and of course you can throw an error directly-- in the constructor of Promise, in the callback of then or catch. If the error is thrown somewhere else, Promise can't control it.

Here are some examples of rejecting Promise:

Function doAsyncOp () {return new Promise (function (resolve, reject) {if (somethingIsBad) {reject ("something is bad");} resolve ("nothing is bad");});} / *-- or-* / function doAsyncOp () {return new Promise (function (resolve, reject) {if (somethingIsBad) {reject (new Error ("something is bad")) } resolve ("nothing is bad");};} / *-- or-- * / function doAsyncOp () {return new Promise (function (resolve, reject) {if (somethingIsBad) {throw new Error ("something is bad");} resolve ("nothing is bad");});}

In general, * uses new Error because it contains other error-related information, such as the line number where it is thrown, and the call stack that may be useful.

Here are some examples of throwing errors that Promise cannot catch:

Function doAsyncOp () {/ / the next line will kill execution throw new Error ("something is bad"); return new Promise (function (resolve, reject) {if (somethingIsBad) {throw new Error ("something is bad");} resolve ("nothing is bad");}) } / / assume `doAsyncOp` does not have the killing error function x () {var val = doAsyncOp () .then (function () {/ / this one will work just fine throw new Error ("I just think an error should be here");}); / / this one will kill execution throw new Error ("The more errors, the merrier"); return val;}

Throwing an error in the Promise of the async function does not cause a scope problem-- you can throw an error in the async function anytime, anywhere, and it will always be caught by Promise:

Async function doAsyncOp () {/ / the next line is fine throw new Error ("something is bad"); if (somethingIsBad) {/ / this one is good too throw new Error ("something is bad");} return "nothing is bad";} / assume `doAsyncOp` does not have the killing error async function x () {var val = await doAsyncOp (); / / this one will work just fine throw new Error ("I just think an error should be here") Return val;}

Of course, we will never run to the second error in doAsyncOp, nor will we run to the return statement, because the error thrown before that has aborted the function.

problem

If you are just starting to use async functions, you need to be careful about the problem of nested functions. For example, if you have another function in your async function (usually a callback), you might think you can use await in it, but you can't. You can only use await directly in the async function.

For example, this code does not work:

Async function getAllFiles (fileNames) {return Promise.all (fileNames.map (function (fileName) {var file = await getFileAsync (fileName); return parse (file);});}

The await on line 4 is not valid because it is used in a normal function. However, you can solve this problem by adding the async keyword to the callback function.

Async function getAllFiles (fileNames) {return Promise.all (fileNames.map (async function (fileName) {var file = await getFileAsync (fileName); return parse (file);});}

You take it for granted when you see it, and even so, you still need to be careful about this situation.

You may also want to know the equivalent code that uses Promise:

Function getAllFiles (fileNames) {return Promise.all (fileNames.map (function (fileName) {return getFileAsync (fileName) .then (function (file) {return parse (file);}

The next question is about treating the async function as a synchronization function. It is important to remember that the code inside the async function runs synchronously, but it immediately returns a Promise and continues to run the external code, such as:

Var a = doAsyncOp (); / / one of the working ones from earlier console.log (a); a.then (function () {console.log ("`a` finished");}); console.log ("hello"); / *-- will output-- * / Promise Object hello `a`finished

You will see that the async function actually uses the built-in Promise. This makes us think about the synchronization behavior in the async function, where others can call our async function through a normal Promise API or use their own async function.

Even if you can't use asynchronous code yourself, you can write it or use tools to compile it to ES5. Asynchronous functions make the code easier to read and easier to maintain. As long as we have source maps, we can use cleaner ES2017 code at any time.

There are many tools that can compile asynchronous functionality (and other ES2015+ features) into ES5 code. If you are using Babel, this is just an example of installing ES2017 preset.

After reading the above, do you have any further understanding of how to use Async functions to simplify asynchronous code? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report