The previous chapter discussed Generator knowledge which is a foundation for understanding async/await. Async /await is a further optimization of synchronization for Promise processing of asynchronous tasks. It has a simple syntax and is a favorite syntactic sugar used by front-end staff. So what exactly is behind async/await:
async/await
What are the advantages?asyncFunction
Constructor.async/await
Syntax, and error catching.async/await
Operating principle.- through
Promise
andGenerator
Function to implement aasync/await
.
1. What are the advantages of async/await
async/await
Keywords allow us to write based in a more concise wayPromise
Asynchronous behavior without the need for intentional chain callspromise
.- More in line with the human way of thinking, use
Promise
“, need to write.then()
Waiting for multiple callbacks to get the internal data, which is still somewhat inconvenient to read,async/await
The order of writing is the order of execution and is easy to understand. Promise
Is a functional programming paradigm that encapsulates asynchronous processes,async/await
Coroutine based mechanism is a more accurate description of asynchronous process.
2. AsyncFunction constructor
Like Generator, async functions are new asynchronous function objects created through constructors. And it’s not a global object.
let AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
async function asyncExpression(){}
let asyncFn = new AsyncFunction()
console.log(asyncExpression instanceof AsyncFunction) // true
console.log(asyncFn instanceof AsyncFunction) // true
// However, it is not recommended to use the new instance in this way, as is the case when creating arrays using literals directly.
// Because function expressions are more efficient, asynchronous functions are parsed by the interpreter along with other code, while using the new body is parsed separately.
Copy the code
The AsyncFunction constructor can be called by omitting new and the effect is the same.
3. Async /await syntax and error catching
When we create an async function, async must return a Promise.
async function foo() {
return 1
}
/ / equivalent
function foo() {
return Promise.resolve(1)}Copy the code
async
Async: async: async: async: async: async: async: async: async: async: async: async: async: async: async: asyncasync
It’s redundant.- It has to do with
Generator
Functions are very similar, you can have more than one insideawait
Perform toawait
The expression pauses and blocks the entireasync
Function and waitawait
After the expressionPromise
Asynchronous results until obtainedPromise
The returnedresovle
Post-result recoveryasync
Function execution.
function promiseFn(){
return new Promise((resovle, reject) = > {
setTimeout(() = > {
resovle('success')},2000)})}async function foo() {
let a = await promiseFn();
console.log(a);
console.log('after await');
}
console.log(foo()) // Output success, after await after 2 seconds
Copy the code
await
Must be inasync
Function is executed internally, otherwise a syntax error is reported.- Due to the
await
Yes Synchronous execution, ifawait
After the asynchronous task error, will cause the following code cannot execute, so usetry/catch
To catch errors, allowing subsequent code to continue execution.
function promiseFn(){
return new Promise((resovle, reject) = > {
setTimeout(() = > {
reject('error')},2000)})}async function foo() {
try{
let a = await promiseFn();
}catch(e) {
console.log(e); // Error is output after two seconds}}Copy the code
5. Await in async function will block the code behind the async function body when executing the Promise asynchronous task, but async function call will not block, all blocks inside it are wrapped in a Promise object to execute asynchronously. This is why await must be used in async functions.
function promiseFn1() {
return new Promise((resovle, reject) = > {
setTimeout(() = > {
resovle('1success')},2000)})};function promiseFn2() {
return new Promise((resovle, reject) = > {
setTimeout(() = > {
resovle('2success')},1000)})}async function foo() {
let a = await promiseFn();
console.log(a);
}
foo()
promiseFna().then(res= > {
console.log(res);
})
// Output after one second: 2SUCCESS
// Output after two seconds: 1SUCCESS
Copy the code
6. Multiple await requests without dependencies on each other can be made at the same time with promise. all requests to speed things up.
function promiseFn1() {
return new Promise((resovle, reject) = > {
setTimeout(() = > {
resovle('success1')},10000)})}function promiseFn2() {
return new Promise((resovle, reject) = > {
setTimeout(() = > {
resovle('success2')},5000)})}async function foo() {
let res = await Promise.all([promiseFn1(), promiseFn2()])
console.log(res); // After 10 seconds ['success1', 'success2']
}
// Get all results in 15 seconds if two await are performed successively.
foo()
Copy the code
4. Operation principle of async/await
Async /await is a callback implemented by generator+yield control flow + Promise. The syntax is encapsulated. So to understand how generator+yield controls flow, I will briefly introduce the concepts of processes, threads, coroutines, and combine generator and async/await syntax to illustrate the implementation process:
process
- The simple idea is to start an instance of an application, open a browser, open vscode, and then start two processes.
- Broadly defined as: 1) it is a running activity of a program with independent functions on a certain data set. 2) It is the basic unit of dynamic execution of the operating system. Process is both the basic allocation unit and the basic execution unit.
- Each process has its own address space, including text area, data area, and stack.
- The process itself does not run and is a container for threads.
- Processes can be in five states: 1) create state 2) Ready state 3) execute state 4) blocked state 5) terminate state **
thread
- Vscode to edit the code, open the command window, open git trace, this is a thread, multiple processes work.
- A process has at least one main thread, and may have more child threads, otherwise there is no point in existence.
- Threads are the smallest unit of execution for an operating system, and threads and processes are scheduled by the operating system in line (CPU).
- A standard thread consists of the current thread ID, current instruction pointer, registers, and stack.
- Multiple threads in the same process can execute concurrently. (Concurrency: two or more threads jump and run at the same time, but only one thread is running at the same time)
- Thread state: 1) ready state 2) running state 3) blocked state.
coroutines
- A thread can have more than one coroutine.
- The scheduling of coroutines is completely controlled by the user.
- Coroutines have their own register context and stack.
- When the coroutine schedules the switch, the register context and stack are saved in other places, and when the switch is cut back, the previously saved register context and stack are restored. The direct operation of the stack basically has no kernel switching overhead, and you can access global variables without locking, so the context switch is very fast
Since JavaScript runtime is single-threaded, it uses a loop mechanism to execute code. To create A Generator function, you can create A coroutine and use yield to switch the coroutine to complete an asynchronous task. The running process is as follows: 1) The coroutine A starts to execute; 2) The execution of coroutine A is suspended halfway, and the execution power is transferred to coroutine B; 3) After a certain period of time, coroutine B returns the execution power; 4) Coroutine A resumes execution; Yield control when it encounters a yield expression, waits for the result to be executed, and when it gets the result, returns the execution authority and prints it. To understand how Generator works, compare async/await:
- create
Generator
Function *, can be interpreted as createAsync
Function of theasync
.
function* gen(){}
async function asy(){}
Copy the code
- Execute to the point where you need to pause
yield
toawait
It has a package insidenext()
, so no manual call is required. butawait
The value returned passes throughasync
Packaging, alwaysPromise
.
function* gen(){
yield 1
}
async function asy(){
await 1
}
Copy the code
So async/await is encapsulated by generator+yield control flow + Promise syntax.
5. Implement a simple async/await
// Defines a promise that simulates an asynchronous request by passing in the ++ argument
function getNum(num){
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(num+1)},1000)})}// The auto-executor is called recursively if a Generator function is not completed
function asyncFun(func){
var gen = func();
function next(data){
var result = gen.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
// This is the Generator function that needs to be executed. The data inside will be called after the promise of one step has been fulfilled
var func = function* (){
var f1 = yield getNum(1);
var f2 = yield getNum(f1);
console.log(f2) ;
};
asyncFun(func);
Copy the code