Synchronous and asynchronous

  • Typically, code is executed from top to bottom. If there are multiple tasks, they must be queued so that the first task is completed before the next task can be executed. This continuous mode of execution is called synchronization.
a();
b();
c();
Copy the code

In the above code, A, B, and C are three different functions, each of which is an unrelated task. In synchronous mode, task A, task B, and task C are executed first. When task B is a long request and task C is a new page display, the page will stall.

  • By asynchrony, a task is not completed continuously. For example, if you have a file-reading task, the first part of the task makes a request to the operating system to read the file, and then the program performs other tasks until the operating system returns the file and processes the file. This discontinuous mode of execution is called asynchrony.
a();
// Send the request immediately
ajax('url',(b)=>{
    // Request back to execute
});
c();
Copy the code

In the code above, the B task is divided into two parts. Some will be executed immediately, and others will be executed upon request. That solves the above problem.

Conclusion: synchronous means everyone works in line, asynchronous means everyone works at the same time.

Asynchronous solutions

1, the CallBack

A CallBack function is called by another party in response to a particular event or condition, rather than directly by the implementation of the function. A function that is triggered to execute after an asynchronous operation has completed.

// The callback function is triggered when the request completes
$.get('url',callback);
Copy the code

Callbacks can be done asynchronously, but any PE that has used jquery suffers from the following code.

$.ajax({
    url:"type".data:1.success:function(a){
        url:"list".data:a,
        success:function(b){
            $.ajax({
                url:"content".data:b,
                success:function(c){
                    console.log(c); }})}})Copy the code

The code above is the legendary callback pyramid, also known as callback Hell. This is pure nested code, but if you add business code to it, you can imagine the readability of the code. It’s fine if you develop it yourself, but if it’s someone else’s code, changing a part of it is enough to drive people crazy.

2. Event publishing and subscription

When we want to read two files, we want to read both files and get the result. This can be done using the EventEmitter class in Node, which has two core methods: on (to register listening events) and EMIT (to emit events).

let fs=require('fs');
let EventEmitter=require('event');
let eve=new EventEmitter();
let arr=[];// Store the read content
// Listen for a data fetch success event and call the callback function
eve.on('ready'.function(d){
    arr.push(d);
    if(arr.length==2) {// Two files of data
        console.log(arr); }}); fs.readFile('./a.txt'.'utf8'.function(err,data){
    eve.emit('ready',data);
});
fs.readFile('./b.txt'.'utf8'.function(err,data){
    eve.emit('ready',data);
});
Copy the code

Request a.tuck and B.tuck file data and publish the ready event when successful. On subscribes to the Ready event, and the ON method executes when the trigger is heard.

The sentry variable

let fs=require('fs');
function after(times,callback){
    let arr=[];
    return function(d){
        arr.push(d);
        if(arr.length==times){ callback(arr); }}}//2 is a sentinel variable that passes the method executed after a successful reading of file data as a callback function
let out=after(2.function(data){
    console.log(data);
})
fs.readFile('./a.txt'.'utf8'.function(err,data){
    out(data);
});
fs.readFile('./b.txt'.'utf8'.function(err,data){
    out(data);
});
Copy the code

The 2 passed in to the after method is a sentinel variable that reads as many files as necessary. Pass after as a callback the number of files that need to be read and the method that successfully reads all the files. Out is the function returned after execution. After each file is successfully obtained, the out method can be executed to obtain the data of all the final files.

The problem with not using callback hell is that you don’t know when the file-reading function is done. Methods that require file data can only be executed when all reads are complete.

3. Generator functions

Generator functions are identified with an asterisk (*) and the yield keyword indicates the token to pause execution. The Generator function is a state machine that encapsulates multiple internal states. A call to Next continues and returns an iterator, so Generator is also a traverser object Generator.

function* read(){
    let a=yield '123';
    console.log(a);
    let b=yield 4;
    console.log(b);
}
let it = read();
console.log(it.next('321')); // {value:'123',done:false}
console.log(it.next(1)); // 1 {value:4,done:false}
console.log(it.next(2)); // 2 {value:2,done:true}
console.log(it.next(3)); // {value:undefined,done:true}
Copy the code

As you can see from the above code, a call to the Generator returns not the result of the function’s execution, but a pointer object to the internal state, the traverser object. The next method of the traverser object must be called to move the pointer to the next state. The internal pointer executes from where the function started or was last fixed until the next yield or return statement is encountered. The value property represents the current internal state value, which is the expression value following the yield statement; The done attribute is a Boolean value indicating whether the traversal is complete.

4, Promise

In the asynchronous history of JavaScript, there were a number of libraries that addressed the drawbacks of callback, and Promise emerged as the winner and was successfully added to the ES6 standard. The Promise function takes as an argument a function that takes resolve and reject. A promise is like a mediation, and it only returns trusted information to the callback, so the callback must be called asynchronously and only once.

let p=new Promise((resolve,reject) = >{
    //to do...
    if(/* Asynchronous operation succeeded */){
        resolve(value);
    }else{ reject(err); }}); p.then((value) = >{
    //success
},(err)=>{
    //failure
})

Copy the code

That way Promise solves the problem of callback hell, like when we read multiple files in a row:

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

read('a.txt').then((data) = >{
    console.log(data);
}).then((a)= >{
    return read('b.txt');
}).then((data) = >{
    console.log(data);
}).catch((err) = >{
    console.log(err);
})
Copy the code

By constantly returning a new Promise, this constant chain of calls eliminates the problem of callback callback hell and non-linear execution of asynchronous code.

Promise also resolves that callback can only catch the current error exception. A Promise is different from a callback. A Promise represents all errors reported by a callback and can be handled by a Promise. So, you can catch previously uncaught exceptions through a catch.

Promise solved callback’s callback hell, but Promise didn’t get rid of callback. So, is there a better way to write it?

5, Async Await

Async functions are a new feature in ES7 that combines Promise with callback and allows us to write asynchronous functions in a synchronous linear fashion, making asynchronous operations more convenient.

let fs=require('fs');
function read(url){
    return new Promise((resolve,reject) = >{
        fs.readFile(url,'utf8'.function(err,data){
            if(err) reject(err); resolve(data); }}})async function r(){
    let a=await read('a.txt');
    let b=await read('b.txt');
    return a+b;
}
r().then((data) = >{
    console.log(data);
});

Copy the code

At this point, we are satisfied with the asynchronous await function. ES7 asynchronous transcoding is already supported with Babel, so you can start experimenting with it in your own projects. Will there be a better solution? With the creativity of our broad program group, I believe there will be.

If you think the article is useful, quickly go to like (⊙﹏⊙)!