preface

Async /await = async/await = await It was officially introduced in ES8, but I don’t find many people around me using async/await. So today, we will talk specifically about what async function is, compared with Promise, what are the advantages of writing and using.

Familiar students, can also review the old to know the new, the text begins…

What is async function?

When it comes to nesting asynchronous callback functions, it’s always annoying, especially when the business logic is complex and requires several Ajax calls to get all the data you need.

From the earliest callback functions, to the Promise object, to the Generator, each time improved, but felt incomplete. They all have an additional level of complexity that requires an understanding of the underlying mechanics of abstraction. So we need a way to handle asynchronous operations more elegantly. So async comes into play.

Async is the syntactic sugar for Generator functions.

It has the following characteristics:

  • Build on promises. Therefore, it cannot be used with the callback function. But it declares an asynchronous function and implicitly returns a Promise. So you can return the variable directly, without the Promise. Resolve conversion.
  • Like promise, it’s non-blocking. Instead of writing then and its callbacks, this reduces the number of lines of code and avoids code nesting. Furthermore, all asynchronous calls can be written in the same code block without defining redundant intermediate variables.
  • Its greatest value is that it makes asynchronous code, in form, more like synchronous code.
  • It is always used with await. And await can only be inside an async function.
  • Await is an operator used to form an expression that blocks subsequent code. If you wait for a Promise object, you get its resolve value. Otherwise, you get the result of an expression.

Why async functions are syntactic sugar

An async implementation is a Generator and an automatic executor wrapped in a single function. The following example comes from ruan’s article “The meaning and usage of Async function”.

async functionfn(args) { // ... } // is equivalent tofunction fn(args) {
    return spawn(function* () {/ /... }); } // the spawn function is the auto-executorfunction spawn(genF) {
    return new Promise(function(resolve, reject) {
        var gen = genF();
        function step(nextF) {
            try {
                var next = nextF();
            } catch(e) {
                return reject(e); 
        }
        if(next.done) {
            return resolve(next.value);
        } 
        Promise.resolve(next.value).then(function(v) {
            step(function() { return gen.next(v); });      
        }, function(e) {
            step(function() { return gen.throw(e); });
        });
    }
    step(function() { return gen.next(undefined); });
  });
}
Copy the code

So async functions are syntactic sugar for Generator functions. In addition, it is relatively new and belongs to the ES8 syntax. However, the transcoder Babel is already supported and can be used after transcoding.

Advantages of Async over Promise

1. It handles then chains better than Promise

function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
    return takeLongTime(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
    return takeLongTime(n);
}
Copy the code

Now use the Promise approach to implement all three steps of processing.

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
        });
}
doIt();
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
Copy the code

If implemented with async/await, it would look like this:

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
}
doIt();
Copy the code

The result is the same as the previous Promise implementation, but the code doesn’t look much cleaner, almost like synchronous code.

2. The median

Now change the business requirements to the same three steps, but each step requires the result of each previous step. The implementation of Pomise looks very dizzy, passing parameters is too troublesome.

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => {
            return step2(time1, time2)
                .then(time3 => [time1, time2, time3]);
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step3(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
        });
}
doIt();
Copy the code

Write async/await:

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time1, time2);
    const result = await step3(time1, time2, time3);
    console.log(`result is ${result}`);
}
doIt();
Copy the code

There are no redundant intermediate values, more elegantly implemented.

3. The debugging

Easier to debug than Promise.

You cannot set breakpoints in a returned arrow function because there is no code block. If you use the debugger step-over in a.then block, the debugger does not go into subsequent.then blocks, because the debugger can only track each step of the synchronized code.

Now, if you use async/await, you don’t have to use arrow functions anymore. You can step on await statements as if they were normal synchronous statements.

conclusion

The appearance of every feature, there is always its use, and only with it, to better understand it.

JavaScript is written asynchronously, from callback functions to Promises, generators, and Async/Await. On the surface, it is just a change of writing method, but in essence, it is a abstraction of language layer again and again. It allows us to implement the same functionality in a simpler way, without having to worry about how the code is executed.

In other words: the ultimate state of asynchronous programming is that you don’t care if it’s asynchronous at all.

reference

  • The meaning and usage of async functions
  • 6 aspects of Async/Await superior to Promise

PS: Welcome to follow my public account “Chao Ge Front-end Small stack” to exchange more ideas and technologies.