When it comes to asynchronous programming, people may think of event listeners, callback functions, publish and subscribe, Promise objects, Generator functions, async functions, etc. This article mainly introduces async functions, which many people consider to be the ultimate solution of asynchronous programming.
What is async function?
In a word, it is the syntactic sugar of Generator functions. Others say it’s the syntactic candy of Promise.
If you are not familiar with Promise objects and Generator functions, you are advised to read the introduction to Promise objects and Generator functions provided by ECMAScript6.
Second, the async
1. The return of async declared functions is essentially a Promise object (important…)
That is, as long as you declare this function async, then no matter what you do internally, it will return a Promise.
async function myAsync () {
return 'hello world'
}
let result = myAsync()
console.log(result)
Copy the code
2. The value returned by the return statement inside the async function becomes the parameter of the callback function of the then method
myAsync().then((val) => {
console.log(val)
})
Copy the code
3. Promise objects returned by async functions will not change state until all Promise objects following the internal await command have been executed, unless a return statement or an error is thrown.
That is, the callback function specified by the THEN method is executed only after the asynchronous operation inside the async function is completed.
function getNum () {
return new Promise((resolve) => {
setTimeout(() => {
resolve(1000)
}, 1000)
})
}
async function myAsync () {
let num = await getNum()
return num + 1000
}
myAsync().then((val) => {
console.log(val)
})
Copy the code
In the above code, myAsync has two operations inside: get num, add 1000, and return the result. The console.log(val) in the then method is executed only when both operations are complete.
Third, await
1. Normally, the await command is followed by a Promise object that returns the result of the object. If it is not a Promise object, the corresponding value is returned.
2. Await means to make the JavaScript engine wait until the await command is finished, and then continue to execute the code following the await command.
3. This behavior does not cost CPU resources because the engine can handle other tasks simultaneously: executing other scripts, handling events, etc.
Let’s look at an example where we can try to write out the result of the execution.
function myAwait () {
return new Promise((resolve) => {
resolve('hello world! ')
})
}
async function myAsync(){
console.log('async begin')
let wait = await myAwait()
console.log(wait)
console.log('async end')
return wait
}
console.log('begin')
let result = myAsync()
console.log(result)
console.log('end')
Copy the code
The above result is the result of execution under Google Chrome, “async end” in “Hello World!” Output later, because await blocks output of “async end”, but “end” in “Hello world!” “Await” only blocks execution of code after “await” in async functions, not any other code.
Four, Promise, Generator, async asynchronous programming examples
Now that we know about async and await, let’s look at a full example.
Let’s take a look at how Promise, Generator, and Async are implemented. Each step requires the result of the previous step.
/* Takes time */function takeLongTime (n) {
return new Promise(resolve => {
setThe Timeout (() = > resolve (n + 1000), n)})} steps / * * /function step1 (n) {
console.log(`step1 with ${n}`)
returnTakeLongTime (n)} step 2 */function step2 (n) {
console.log(`step2 with ${n}`)
returnTakeLongTime (n)} step 3 */function step3 (n) {
console.log(`step3 with ${n}`)
return takeLongTime(n)
}
Copy the code
1. Promise realization:
function doIt () {
let time1 = 1000
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`)})}doIt()
Copy the code
2. Implementation of Generator:
The /** actuator * function does not run automatically, we need the actuator */function run (generator) {
let iterator = generator()
let result = iterator.next()
function step () {
if(! result.done) {let promise = Promise.resolve(result.value)
promise.then((value) => {
result = iterator.next(value)
step()
}).catch((error) => {
result = iterator.throw(error)
step()
})
}
}
step()
}
function *doIt () {
let time1 = 1000
let time2 = yield step1(time1)
let time3 = yield step2(time2)
let result = yield step3(time3)
console.log(`result is ${result}`)
}
run(doIt)
Copy the code
3. Implementation of Async:
async function doIt () {
let time1 = 1000
let time2 = await step1(time1)
let time3 = await step2(time2)
let result = await step3(time3)
console.log(`result is ${result}`)}doIt()
Copy the code
The execution results of the three methods are as follows:
Compare the above three implementations:
1. Because the then method of a Promise returns a new Promise, a Promise can be programmed asynchronously through chain calls.
2. Async and Generator functions are more interesting. Async functions replace the asterisk (*) of Generator functions with async, yield with await, and have built-in actuators, and nothing more.
3. It is not difficult to find that the writing method of async is more semantic and clearer.
Five, use matters needing attention
1. Await the Promise object after the await command, and the result may be rejected, so it is better to await the await command in the try… In the catch block.
async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); }} // Another way to write asyncfunction myFunction() {
await somethingThatReturnsAPromise()
.catch(function (err) {
console.log(err);
});
}
Copy the code
2. Asynchronous operations following multiple await commands, preferably firing them at the same time if there is no secondary relationship.
function getA () {
return new Promise((resolve) => {
setTimeout(() => {
resolve('A')}, 1000)})}function getB () {
return new Promise((resolve) => {
setTimeout(() => {
resolve('B')
}, 1000)
})
}
async function myAsync () {
let A = await getA();
console.log('A: ', A)
let B = await getB();
console.log('B: ', B)
}
myAsync()
Copy the code
In the above code, getA and getB are two independent asynchronous (that is, non-dependent) operations written as a secondary relationship. This is time consuming because getB will not be executed until getA is complete, and they can be fired at the same time.
// asyncfunction myAsync () {
let [A, B] = await Promise.all([getA(), getB()])
console.log('A: ', A)
console.log('B: ', B)
}
myAsync()
Copy the code
// asyncfunction myAsync () {
let aPromise = getA()
let bPromise = getB()
let A = await aPromise
let B = await bPromise
console.log('A: ', A)
console.log('B: ', B)
}
myAsync()
Copy the code
GetA and getB are both fired at the same time, which shortens the execution time of the program.
3.await command can only be used in async functions, if used in normal functions, an error will be reported.
Six, the summary
The async keyword in front of the function does two things:
1. Make this function return a promise. 2. Allow to use await inside the function, which in turn makes the JavaScript engine wait until the promise is complete and throw an exception if there is an error, otherwise return the result.
Together, these two keywords provide an easy-to-understand way to control asynchronous programming and are easy to read and write.
7. Additional questions: the execution sequence of async, Promise and setTimeout
I believe you have a certain understanding of Promise, Generator and Async. If you add setTimeout, do you still have a clear sequence of code execution?
Let’s see a write the execution result of the problem, I believe many students have encountered the interview, is not very meng force!!
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
},0)
async1()
new Promise((resolve) => {
console.log('promise1')
resolve()
}).then(() => {
console.log('promise2')
})
console.log('script end')
Copy the code
Results (the results may vary depending on the browser, the following results are Google) :
Please remember the rules of execution: SetTimeout has the lowest priority, not as high as async and Promise (actually async and promise are the same, because async method calls return a promise object). Async and promise. Then depend on who enters the task queue first, which has a first-in, first-out concept.
By following this rule, you should be able to write execution results in no time.
The detailed steps are here