What is synchronization?

Synchronization is when a piece of code is executed, and the rest of the code cannot be executed until the result is returned, but once the execution is complete and the return value is returned, the rest of the code can be executed. In other words, subsequent code execution will be blocked until the result is returned, which is called synchronization.

What is asynchrony?

Asynchrony means that when code executes an asynchronous procedure call, the code does not immediately return the result. Instead, after an asynchronous call has been made, the call is typically processed by a callback function and the result is retrieved. When an asynchronous call is made without affecting the execution of the code that follows the block, it is called asynchronous.

Why asynchrony in JS programming?

We all know that JavaScript is single threaded, so what does it mean if JS executes code synchronously? This may cause a block, if we have a piece of code to execute, if we use synchronous mode, then it will block the following code execution; With asynchrony it does not block, and we do not need to wait for the result of asynchronous code execution to return. We can continue to execute the code logic after the asynchronous task. So in JS programming, asynchronous programming is used a lot, which is why I’m going to focus on this section.

JS asynchronous programming development process

Having said the basic concept of asynchronous programming, let’s look at the implementation of JS asynchronous programming in chronological order.

The callback function

From the perspective of historical development, in order to realize asynchronous PROGRAMMING of JS in the early years, callback functions are generally adopted, such as the callback of typical events, or setTimeout/ setInterval is used to realize some asynchronous programming operations, but there is a very common problem in using callback functions to realize. That’s callback hell.

Here I’ve outlined a scenario that you might encounter in real life development, and let’s look at the code.

fs.readFile(A, 'utf-8'.function(err, data) {
    fs.readFile(B, 'utf-8'.function(err, data) {
        fs.readFile(C, 'utf-8'.function(err, data) {
            fs.readFile(D, 'utf-8'.function(err, data) {
                //....
            });
        });
    });
});
Copy the code

If the contents are helpful to you, please use your hands to help small make up: click on this link to add a chicken leg: github.crmeb.net/u/xingfu

As you can see from the above code, the logic is to first read the text content of A, then read B from the text content of A, and then read C from the content of B. To implement this business logic, the code implemented above could easily form callback hell. There are also many scenarios where callbacks enable asynchronous programming, such as:

  1. Callback to Ajax requests;
  2. Callback in timer;
  3. Event callback;
  4. Some method callbacks in Nodejs.

While the readability and code maintainability of asynchronous callbacks are acceptable if the hierarchy is small, once the hierarchy becomes large, the callback hell will be involved in all of the above asynchronous programming scenarios. Let’s take a look at what asynchronous programming would look like if we made Promise for this business scenario.

Promise

In order to solve the problem of callback hell, the community later proposed the solution of Promise, and ES6 wrote it into the language standard, using the Promise implementation way to solve the problem of callback hell to a certain extent.

Let’s look at the above scenario: first read text A, then read file B based on text A, and then read file C based on the content of file B. Let’s take a look at the code to see what such an implementation looks like after transforming it with Promise.

function read(url) {
    return new Promise((resolve, reject) = > {
        fs.readFile(url, 'utf8'.(err, data) = > {
            if(err) reject(err);
            resolve(data);
        });
    });
}

read(A).then(data= > {
    return read(B);
}).then(data= > {
    return read(C);
}).then(data= > {
    return read(D);
}).catch(reason= > {
    console.log(reason);
});
Copy the code

Can be seen from the above code, the callback hell for such improvement, readability do have certain ascend, advantage is asynchronous operations can be in the process of synchronous operation, to avoid the layers of nested callbacks, but Promise there are still some problems, even if is to use the Promise of chain calls, if the operation too much, There is no fundamental solution to the problem of callback hell, just a new way of writing that makes it more readable, but still difficult to maintain. However, Promise also provides an ALL method, which might work better for this business scenario code.

If the contents are helpful to you, please use your hands to help small make up: click on this link to add a chicken leg: github.crmeb.net/u/xingfu

Let’s look at a snippet of code implemented with ALL.

function read(url) {
    return new Promise((resolve, reject) = > {
        fs.readFile(url, 'utf8'.(err, data) = > {
            if(err) reject(err);
            resolve(data);
        });
    });
}
// With promise.all, you can implement multiple asynchronous parallel executions and get the final result at the same time
Promise.all([read(A), read(B), read(C)]).then(data= > {
    console.log(data);
}).catch(err= > 
    console.log(err)
);
Copy the code

Does this look clearer and more obvious than using Promise directly? Let’s take a look at another asynchronous JS programming approach, which is also the Generator approach introduced in ES6.

Generator

Generator is also an asynchronous programming solution. The best feature of the Generator is that it can yield execution of functions. Generator functions can be seen as containers for asynchronous tasks and use yield syntax whenever they need to be paused. Generator functions are usually used in conjunction with yield. Generator functions return iterators at the end. If you don’t know much about iterators, you can take a look at this section for yourself.

Let’s look at a simple use of Generator, as shown in this code.

function* gen() {
    let a = yield 111;
    console.log(a);
    let b = yield 222;
    console.log(b);
    let c = yield 333;
    console.log(c);
    let d = yield 444;
    console.log(d);
}

let t = gen();
t.next(1); // When next is called for the first time, the argument passed is invalid, so no result is printed
t.next(2); // a output 2;
t.next(3); // b output 3;
t.next(4); // c output 4;
t.next(5); // d output 5;
Copy the code

As you can see from the above code, the first next is executed but does not output the result. Each subsequent next is passed in and printed out. After the last yield for next is executed, the console prints “{value: Undefined, done: true} “, indicating that the Generator is complete, that is, done: true.

After looking at the Generator mode, let’s look at one last async/await implementation.

async/await

After ES6, a new asynchronous solution was proposed in ES7: Async /await, async is the syntactic sugar of Generator functions, async/await has the advantage of clean code (unlike with promises where you need to write a lot of then method chains) and can handle callback hell. Writing async/await makes JS asynchronous code look like synchronous code. In fact, the goal of asynchronous programming development is to make asynchronous logic code look as easy to understand as synchronization.

If the contents are helpful to you, please use your hands to help small make up: click on this link to add a chicken leg: github.crmeb.net/u/xingfu

Let’s look at the basic usage of async/await as shown below.

function testWait() {
    return new Promise((resolve,reject) = >{
        setTimeout(function(){
            console.log("testWait");
            resolve();
        }, 1000); })}async function testAwaitUse(){
    await testWait()
    console.log("hello");
    return 123;
    // Output order: testWait, hello
    // Line 10 if no await is used: hello, testWait
}

console.log(testAwaitUse());
Copy the code

In the normal order of execution, the callback of testWait will be executed one second later because of the setTimeout timer. However, the callback will be executed with await keyword. The testAwaitUse function waits for the testWait function to complete before printing hello. But if you remove await, the order in which the results are printed changes.

Therefore async/await is not only a way of asynchronous programming of JS, but also has readability close to synchronous code, making it easier to understand.

If the contents are helpful to you, please use your hands to help small make up: click on this link to add a chicken leg: github.crmeb.net/u/xingfu

conclusion

In this lecture, I take you through the asynchronous programming of JS. I hope that by explaining these ways, you can form a global understanding of JS asynchronous programming, including Promise, Generator and async/await related knowledge points, I will specifically analyze and mine each point in more detail in the later courses.

I’ve put together a table that summarizes the lecture.

At this point, if you can make good promises on your own, you’ll be able to meet basic needs for interviews and daily work.