Illustration and examples of using Async

Time:2020-11-22

brief introduction

In JavaScript ES7async/awaitSyntax makes asynchronous promise easier. If you need to get data asynchronously from multiple databases or APIs in some order, you can use noodle code consisting of promise and callback.async/awaitConstruction allows us to express this logic more succinctly, and the code is easier to read and maintain.

This tutorial uses diagrams and simple examples to explain JavaScriptasync/awaitGrammar and semantics.

Before we start, let’s start with aPromiseStart with a brief overview of. If you already know JSPromise, please feel free to skip this section.

Promises

In JavaScript,PromisesRepresents the abstraction of non blocking asynchronous execution. If you know other languages, jspromise and JavaFutureOr CTasksimilar.

PromisesTypically used for network and I / O operations – such as reading from a file or making an HTTP request. If we don’t need to block the current “thread” execution, we can generate an asynchronousPromisesAnd use the then method to pass in a callback function that will be triggered when promise completes. The callback function itself can returnPromiseSo we can chain callPromise

For simplicity, in all examples, we assume thatrequest-promiseIs already installed and can be loaded as follows:

var rp = require('request-promise');

Now we can make a simple HTTP get request and return aPromise

const promise = rp('http://example.com/')

Now, let’s take an example:

console.log('Starting Execution');

const promise = rp('http://example.com/');
promise.then(result => console.log(result));

console.log("Can't know if promise has finished yet...");

We are hereLine 3There’s a new onePromiseAnd then in theLine 4Attach a callback function.PromiseIt’s asynchronous, so when we arriveLine 6We don’t knowPromiseWhether it has been completed. If we run the code multiple times, we may get different results each time. More specifically, any post commitment code is associated withPromiseAt the same time.

stayPromiseWe have no reasonable reason to stop the current sequence of operations until it is done。 This is similar to Java’sFuture.getInstead, it allows us to block the current thread until it completes in the future. In JavaScript,We can’t waitPromisecomplete。 stayPromiseThe only way to execute code after completion is through thethenMethod passes in the callback function.

The following figure depicts the calculation process of this example:

Illustration and examples of using Async

PromiseThe calculation process of. Calling thread cannot waitPromise。 stayPromiseAfter that, the only way to execute the code is through thethenMethod to specify the callback function.

Only whenPromiseWhen successful, the callback function can be executed. If it fails (due to a network error, for example), the callback function will not execute. To deal with failedPromiseYou can go throughcatchPass in another callback:

rp('http://example.com/').
    then(() => console.log('Success')).
    catch(e => console.log(`Failed: ${e}`))

Finally, for testing purposes, we can easily create aPromise.resolveandPromise.rejectMethod created successfully or failedPromise

const success = Promise.resolve('Resolved');
// Will print "Successful result: Resolved"
success.
    then(result => console.log(`Successful result: ${result}`)).
    catch(e => console.log(`Failed with: ${e}`))


const fail = Promise.reject('Err');
// Will print "Failed with: Err"
fail.
    then(result => console.log(`Successful result: ${result}`)).
    catch(e => console.log(`Failed with: ${e}`))

Problem combinedPromise

Use aPromiseIt’s intuitive and simple. However, when we need to program complex asynchronous logic, we may have severalPromiseend. These are writtenPromiseAnd anonymous callbacks can easily lose control of your code.

For example, suppose we need to write a program:

  1. Initiate HTTP request, wait for completion, and print the result;
  2. After returning, make the other two HTTP parallel calls;
  3. When they are all finished, print the results.

The following code snippet demonstrates how to do this:

// Make the first call
const call1Promise = rp('http://example.com/');

call1Promise.then(result1 => {
    // Executes after the first request has finished
    console.log(result1);

    const call2Promise = rp('http://example.com/');
    const call3Promise = rp('http://example.com/');

    const combinedPromise = Promise.all([call2Promise, call3Promise]);
    combinedPromise.then(arr => {
        // Executes after both promises have finished
        console.log(arr[0]);
        console.log(arr[1]);
    })
})

We start with the first HTTP request and run the callback function (lines 1-3) when it completes. In the callback, we generate two for subsequent HTTP requestsPromise(lines 8-9). these two items.PromiseAt the same time, we need to schedule a callback to be called when they are all completed. So we need to passPromise.all(line 11) combine them into a singlePromiseWhen they are complete, they can be called correctly. Then we pass in another callback of the printed result (lines 14-15).

The following figure describes the calculation process:

Illustration and examples of using Async

For such a simple example, we end up with two nested callback functions that must be used Promise.all To synchronize concurrencyPromise。 What if we have to run some more asynchronous operations or add error handling? This method can be easily adapted to usePromise.allAnd multiplethenLink up the chain noodle code.

We can rewrite the above example to use “promise chaining”, as follows:

// Make the first call
const call1Promise = rp('http://example.com/');

call1Promise.then(result1 => {
    // Executes after the first request has finished
    console.log(result1);

    const call2Promise = rp('http://example.com/');
    const call3Promise = rp('http://example.com/');

    return Promise.all([call2Promise, call3Promise]);
}).then(arr => {
    // Executes after both promises have finished
    console.log(arr[0]);
    console.log(arr[1]);
})

This is more readable, although we still need to link two callback functions and use themPromise.all

Async function

The async function returnsPromiseShort for function.

For example, the following definitions are equivalent:

function f() {
    return Promise.resolve('TEST');
}

// asyncF is equivalent to f!
async function asyncF() {
    return 'TEST';
}

Similarly, an async function that throws an exception is equivalent to returningreject PromiseFunction of:

function f() {
    return Promise.reject('Error');
}

// asyncF is equivalent to f!
async function asyncF() {
    throw 'Error';
}

Await

When we generate commitments, we can’t synchronize waiting for completion. We can only go through one callback. Do not allow waiting for promises to encourage development of non blocking code. Otherwise, developers will be tempted to perform blocking operations because it is easier than using promises and callbacks.

When we createPromiseWe can’t synchronize to wait for completion. We can only go through one callback. No waiting allowedPromiseTo encourage the development of non blocking code. Otherwise, it will be easier for developers to use an operation that locks the current thread, because it is better than using thePromiseAnd callback is easier.

However, in order to synchronizePromiseWe need to allow them to wait for each other. In other words, if the operation is asynchronous (that is, encapsulated inPromiseYou should be able to wait for another asynchronous operation to complete. But how does the JavaScript interpreter know if an operation is inPromiseRun in?

The answer is in theasynckeyword. eachasyncFunctions return aPromise。 As a result, the JavaScript interpreter knowsasyncAll operations in the function are encapsulated in thePromiseRun asynchronously. So you can make them wait for othersPromiseDo not proceed until done.

When we use the await keyword. It can only be used forasyncFunction and allow us to wait synchronouslyPromise。 If we wereasyncUse outside of functionPromiseWe still need to use the callback function:

async function f(){
    // response will evaluate as the resolved value of the promise
    const response = await rp('http://example.com/');
    console.log(response);
}

// We can't use await outside of async function.
// We need to use then callbacks ....
f().then(() => console.log('Finished'));

Now let’s look at how we solved the problem in the previous section:

// Encapsulate the solution in an async function
async function solution() {
    // Wait for the first HTTP call and print the result
    console.log(await rp('http://example.com/'));

    // Spawn the HTTP calls without waiting for them - run them concurrently
    const call2Promise = rp('http://example.com/');  // Does not wait!
    const call3Promise = rp('http://example.com/');  // Does not wait!

    // After they are both spawn - wait for both of them
    const response2 = await call2Promise;
    const response3 = await call3Promise;

    console.log(response2);
    console.log(response3);
}

// Call the async function
solution().then(() => console.log('Finished'));

In the above code snippet, we encapsulate the solution in theasyncFunction. This allows us to wait directlyPromiseTo avoid the need for a callback. Finally, we callasyncFunction, which simply generates a wrapper to call the otherPromiseLogicalPromise

In fact, in the first example (Noasync/await), thesePromiseIt will start in parallel. In this case, we do the same (lines 7-8). Please note that untilLines 11-12When we useawaitUntil twoPromiseIt’s all done. After that, we know the twoPromiseIt’s all done (similar to the one used in the previous examplePromise.all(…) and then (…)).

The actual calculation process is equivalent to that described in the previous section. However, the code is more readable and intuitive.

Under guidance,async/awaitIn fact, it turns out to bePromise, and then call back. In other words, it’s usingPromiseGrammar sugar. Every time we wait, the interpreter generates onePromiseAnd put the rest of the operation from the asynchronous function into a callback.

Consider the following examples:

async function f() {
    console.log('Starting F');
    const result = await rp('http://example.com/');
    console.log(result);
}

The basic calculation process of F function is as follows. Since f is asynchronous, it will also run in parallel with its caller

Illustration and examples of using Async

Function f starts and generatesPromise。 At that point, the rest of the function is encapsulated in a callback function, and thePromisePlan to execute after completion.

error handling

In most of the previous examples, we assume thatPromiseSuccessfully implemented. So waitPromiseReturn value. If we wait for failurePromiseThis will cause an exception in the asynchronous function. We can use standardtry/catchTo deal with it:

async function f() {
    try {
        const promiseResult = await Promise.reject('Error');
    } catch (e){
        console.log(e);
    }
}

IfasyncFunction does not handle exceptions, whether rejected byPromiseIf it is caused by other errors, the rejected will be returnedPromise

async function f() {
    // Throws an exception
    const promiseResult = await Promise.reject('Error');
}

// Will print "Error"
f().
    then(() => console.log('Success')).
    catch(err => console.log(err))

async function g() {
    throw "Error";
}

// Will print "Error"
g().
    then(() => console.log('Success')).
    catch(err => console.log(err))

This makes it easy for us to handle rejected ones through known exception handling mechanismsPromise

discuss

Async/awaitIt’s a kind of rightPromiseThe language supplement of. It allows us to use fewer templatesPromise。 But,Async/awaitCan’t replace purePromiseThe need for. For example, if we call from a normal function or a global scopeAsyncFunction, we will not be able to use itawaitAnd will appeal to vanillaPromise

async function fAsync() {
    // actual return value is Promise.resolve(5)
    return 5;
}

// can't call "await fAsync()". Need to use then/catch
fAsync().then(r => console.log(`result is ${r}`));

I usually try to encapsulate most of the asynchronous logic in one or several asynchronous functions, which are invoked from non asynchronous code. This minimizes what I need to writetry/catchThe number of callbacks.

Async/awaitStructure is more in line withPromiseGrammar sugar. eachAsync/awaitThe structure can be simplePromiserewrite. So, it’s a matter of style and brevity.

Pay attention to my WeChat official account, and more quality articles are pushed regularly.
Illustration and examples of using Async

Translated from http://nikgrozev.com/2017/10/…

Recommended Today

Array of algorithms — sum of three numbers

Sum of three numbers difficultysecondary Here is an array of N integersnums, judgmentnumsAre there three elements a, B, C in a such that a + B + C = 0? Please find all triples that satisfy the condition and do not repeat.be careful:The answer cannot contain duplicate triples. Example:Given array nums = [- 1, 0, […]