JavaScript asynchronous programming and synchronous mode

JavaScript asynchronous programming

The reason why javaScript adopts single thread: because javaScript is used to realize the dynamic interaction of pages, the core of interaction needs to operate dom. This situation determines that it must use single thread model, otherwise complex thread synchronization problems will occur; For example, in the case of multithreading, if one thread modifies the DOM and one thread deletes the DOM at the same time, the browser cannot take which worker thread as the standard.

Synchronous mode

Code tasks are executed in turn. Subsequent code tasks can only be executed after the previous task is executed. If the previous task is not executed, the subsequent task will not be executed. [synchronization model is not executed at the same time, but queued]. The program execution sequence is consistent with the writing sequence.

The advantages are easy to understand, simple, reading and thinking logic.

The disadvantage is that in case of time-consuming or long-time tasks, there will be waiting, that is, blocking.

Using asynchronous processing ajax, the node file is a time-consuming task to read these notes.

console.log('start')
function bar(){
    console.log('bar')
}

function fun() {
    console.log('fun')
    bar();
}
fun()
console.log('end')

Code run

1. Loading the code and pressing an anonymous function call into the call stack is equivalent to putting all the code into the anonymous function for calling and execution, and then executing each line of code line by line.

2. Set the console Log ('start ') is taken out and put into the execution stack for execution. After execution, it is removed.

3. bar and foo functions and variables are not called when declared and will not be placed on the call stack.

4. Put fun() on the call stack for execution. The executed function fun will be console Log ('fun ') is placed on the call stack for execution. After execution, move out of the console, put bar() into the call stack, execute the new function bar [the order of the call stack is [bar > fun > anonymous]], and move the console Log ('bar ') is taken out for execution, removed after execution, and bar function is removed from the call stack after execution. At this moment, there is only [fun, anonymous] left in the call stack

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-vwc1lctc-1624783485987) (C: \ users \ Tom \ appdata \ roaming \ typora \ user images \ image-20210621080838137. PNG)]

5. After the execution of the fun function, it is removed from the call stack, leaving only [anonymous] on the call stack

6. Set the console Log ('end ') is taken out for execution. After execution, the overall code execution is completed.

7. The call stack will be emptied.

Call stack

Generally speaking, JavaScript maintains the executing task table on the execution engine, which records some things being done. When all the tasks in it are cleared, this round of work is over.

Asynchronous mode

It will not wait until the current task is completed. For a time-consuming task, the next task will be executed immediately after it is started. The logic of the time-consuming task is defined by the callback function. After the time-consuming task is completed, the incoming callback function will be called automatically.

Without asynchronous mode, single threaded javaScript cannot handle a large number of time-consuming tasks at the same time.

The execution sequence of asynchronous code is relatively chaotic, and there is no synchronous code, which is easy to understand

Code execution analysis asynchronous mode

//Asynchronous code example and execution analysis

console.log(1)
setTimeout(function() {
    console.log(2)
},1800)
setTimeout(function() {
    console.log(3)
    setTimeout(function() {
        console.log(4)
    },799)
},1000)
console.log(5)

Analyze the results of the above code execution:

The environment of the internal api of the Web API, because it is executed on the web platform

Event Loop event loop

Queue event queue / callback queue

Call Stack, console

If shown, there are more Event Loop, Event Loop and message queue than synchronization code

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-xjkxxxia-1624783485989) (C: \ users \ Tom \ appdata \ roaming \ typora user images \ image-20210621215101249. PNG)]

1. Load the js code, then press in the Call stack call stack (anonymous anonymous global call), and execute each line of code in turn.

2. console synchronizes the api, presses the Call stack, executes, outputs, and moves out of the Call stack.

3. SetTimeout is pushed into the call stack. The internal of the setTimeout function is an asynchronous call. You need to pay attention to what the internal api does. The internal WEB api starts the countdown timer for time1 and waits for execution alone for 1.8s. SetTimeout moves out of the call stack [the countdown works separately and will not be affected by js threads]

4. The second timer starts a timer for time2, which is put into the web api to wait for the call to execute for 1s.

5. console is a synchronous api that executes, outputs, and moves out of the call stack.

6. After the anonymous call is executed, clear the air conditioning stack.

7. When there is no task in the call stack, the call stack is suspended. Event loop mainly listens to the call stack and message queue. When the task of the call stack ends, the first task will be taken from the event queue and placed on the call stack for execution.

8. The countdown of time1 is longer than the countdown of time2, so the countdown of time2 will end first and put it in the event queue. The countdown of time2 will end and put it in the event queue [the message queue is empty at the moment before putting it, that is to say, put it in the first], wait for the event cycle call, and put it in the event queue [that is, the second place] after the countdown of time1, The event loop takes out the task time2 first put into the event queue and puts it into the call stack for execution.

9. When the event queue changes, the event loop will listen and put the first task of the event queue on the call stack for execution, that is, the function of time2 is placed on the call stack for execution. After execution, move time2 out of the call stack.

10. Take out the second task of the event queue and execute it. If there is another timer time3 in it, it will reopen the timer and wait alone.

11. The timing of timer 1.8s is shorter than that of time2 1s+iner 1s. time1 will be put on the call stack for execution before inner.

12. After timer1 finishes clearing the air conditioning stack, the inner timer ends and is placed in the event queue. After the event loop monitors the changes of the event queue, it puts the inner into the call stack for execution. After execution, it clears the air conditioning stack and ends execution.

Event queue

A to-do worksheet

js engine first acts as all the tasks of the call stack, and then takes out the tasks from the call stack through the event loop and puts them into the call stack for execution, and so on. During the execution process, you can put tasks into the event queue at any time, which is more like push ing a task into the message queue, and then queue up in the message queue to wait for the event loop to be taken out and put into the call stack for execution.

js thread execution

javaScript is single threaded, but browsers are not single threaded.

The internal api called by javaScript is not single threaded. For example, there is a separate thread inside the timer, which is responsible for the countdown of time. When the time comes, the callback will be put into the event queue, which is executed by a separate thread.

The so-called single thread in js means that the thread executing code is a thread.

The internal api uses a separate thread to perform the waiting operation.

There are time-consuming things to wait in life. Someone has to wait, but it won't let js threads wait.

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-maiwbfar-1624783485992) (C: \ users \ Tom \ appdata \ roaming \ typora \ user images \ image-20210621225818210. PNG)]

Distinction between synchronous and asynchronous

Synchronization and asynchrony are not the different ways of code, but whether the API provided by the running environment is executed in a synchronous or asynchronous way.

Synchronization will wait for execution, and asynchrony will not wait for execution. After asynchronously issuing the instruction to start the task, the next task will be executed.

Asynchronous difference value

Time difference, setting millimeter execution effect, it should be that the timer can't be accurate to a few milliseconds. If you're wrong, please give advice.

console.log(1)
setTimeout(function() {
    console.log(2)
},1800)
setTimeout(function() {
    console.log(3)
    setTimeout(function() {
        console.log(4)
        setTimeout(function() {
            console.log(5)
        },1)
    },787)
},1000)
console.log(6)
//It was 163452 before updating Google and 163425 after updating

console.log(1)
setTimeout(function() {
    console.log(2)
},1800)
setTimeout(function() {
    console.log(3)
    setTimeout(function() {
        console.log(4)
        setTimeout(function() {
            console.log(5)
        },1)
    },786)
},1000)
console.log(6)
//163425 before Google update and 163425 after Google update


//node results
console.log(1)
setTimeout(function() {
    console.log(2)
},1800)
setTimeout(function() {
    console.log(3)
    setTimeout(function() {
        console.log(4)
    },800)
},1000)
console.log(5)
//1,5,3,2,4

console.log(1)
setTimeout(function() {
    console.log(2)
},1800)
setTimeout(function() {
    console.log(3)
    setTimeout(function() {
        console.log(4)
    },790)
},1000)
console.log(5)
//15342

Differences before and after update

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-jgraxgyq-1624783485995) (C: \ users \ Tom \ appdata \ roaming \ typora user images \ image-20210621214434419. PNG)]

Callback function

All asynchronous programming is based on callback functions. Callback functions can be understood as things you want to do. Wait for the results to do (for example, after the 10s timer is over, the automatic callback function performs some operations). The caller defines the callback function, The performer (asynchronous task performer) executes the callback function defined by the caller after waiting. The setTimeout(fun,100) caller defines the fun callback function in setTimeout, performs the fun callback function of the caller after the wait timer ends.

The essence of Promise is to define the task at the end of asynchronous task through callback function

setTimeout(function(){ //The caller defines the function, and the performer waits for the function to be executed
    console.log(1111)
},1000)

Promise

concept

Advantages: it solves the callback problem of function nesting.

The state of promise object is not affected by the outside world, indicating whether the final result of an asynchronous task is success or failure; Promise has three statuses: pending, Resolved and Rejected

Promise makes a commitment to the outside world. The promised thing is Pending (in progress). Once the state changes (change the promised state according to the result), it will not change again. There are only two changed states: from Pending to successfully Resolved and Pending to Rejected. Once these two changes happen, the state will be fixed and will not change again, Keep this result.

For example, Cheng Ruo told you to get up (Pending) and didn't wake you up at last (the result was changed from Pendng to Rejected). No matter how to explain, if the promise of Cheng ruo's wake-up service failed, it's impossible to say that this promise was reached. Even if we say that we must wake up next time, we must wake up the other Cheng Ruo next time.

Basic Usage

First output the printed content, and then throw the then exception

The then method in Promise will be put into the event queue and will not be executed until the synchronization code is executed

// Basic use

const prom = new Promise((resolve, reject) => { //Initiate a commitment
    //Fulfill the promise in the callback

    // Successfully deliver on commitments
    // resolve({name:'start'})

    //Failed to fulfill the promise
    reject(new Error('Woo woo failed')) 
}) 
prom.then((data) => {
    console.log(data) //{name:'start'}
}, (err) => {
    console.log(err) //Throw exception
})

for(var i = 0; i < 1000000000; i++) {
    if(i === 999999999) console.log(i)
}
console.log('end')

Promise encapsulates ajax

Five steps for ajax requests

1. Create XMLHttpRequest asynchronous object

const xhr = new XMLHttpRequest();

2. Set the request method and request address. The open object has three parameters: request method (get|post), request address and asynchrony.

xhr.open('GET', 'pageage.json', true);

3. Send request with send

xhr.open()

4. The function onreadystatechange is used to monitor the change of readyState

//The onreadystatechange event calls this function when the readyState changes
xhr.onreadystatechange = function() {
	/**
     * readyState Five states of
     * 0:Request not initialized
     * 1: Server connection established
     * 2: Request accepted
     * 3: Request processing
     * 4: The request has been completed and the response is ready (the data is down, and you can use status to get the http status code)
    */
    if(xhr.readyState === 4) {
           if(xhr.status === 200){ //Status code 200 request succeeded
                //5. Receive returned data
                console.log(xhr.responseText)
           }
     }
}
ajax implementation of get request
/***
 * ajax Request five steps
 * 1,Create XMLHttpRequest object
 * 2,Set request method and address 
 * 3,Then send sends the request
 * 4,Monitoring state change
 * 5,Accept returned data
 */
 function ajax(){
    //1. Create XMLHttpRequest object
    const xhr = new XMLHttpRequest();
    
    //2. Set request mode and request status
    xhr.open("GET", 'package.json', true);
    xhr.responseType = 'json'; //Add this type to return json format data
    
    //3. Send request with send
    xhr.send()
    
    //4. Monitoring status change, XHR Onload = function() {} is also OK
    xhr.onreadystatechange = function (){
        //The onreadystatechange event calls this function when the readyState changes
        /**
         * readyState Five states of
         * 0:Request not initialized
         * 1: Server connection established
         * 2: Request accepted
         * 3: Request processing
         * 4: The request has been completed and the response is ready (the data is down, and you can use status to get the http status code)
        */
       if(xhr.readyState === 4) {
           if(xhr.status === 200){ //Status code 200 request succeeded
                //5. Receive returned data
                console.log(xhr.responseText)
                console.log(JSON.parse(xhr.responseText))
           }
       }
    }
}
ajax()

Promise common misunderstandings

Promise try to flatten asynchrony instead of nesting

Promise chained call

1. The then method of the Promise object will return a new Promise object. All users can use then to make chain calls.

2. The latter then method is actually the Promise callback returned by the previous then.

3. The return value of the callback function in the previous then method is used as the parameter of the callback of the subsequent then method.

4. If Promise is returned in the callback, the callback of the then method will wait for its structure

//call chaining 
ajax().then((res) => {
    console.log('then~',res)
    return res;
}).then((res) => {
    console.log(res)
    return ajax()
}).then((res) => {
    console.log(res)
})

Promise exception handling

Using catch

reject handles the Promise exception: Code exceptions, errors and request failures will be executed

ajax('package.jso').then((res) => {
    console.log('then~',res)
    return ajax('package'); //If the return is to an exception, the second parameter of then cannot be caught
},(err) => {
    console.log(err)
}).then((res) => {
    console.log(res)
})

//Use catch to handle exceptions for the whole chain, because any errors will be passed down until they are caught [it is recommended to use the chain]
ajax('package.json').then((res) => {
    console.log('then~',res)
    return ajax('package.jso')
}).then((res) => {
    console.log(res)
}).catch((err) => {
    console.log(err)
})
Unhandledrection event

When Promise is rejected and no exception is caught by manual reject, the unhandledrejection event will be triggered;

Every possible exception should be caught explicitly, not thrown to the global processing.

//Global capture, write is not recommended
window.addEventListener('unhandledrejection',(event) => {
console.log(event)
const {reason, promise} = event;
console.log(reason,promise);
event.preventDefault()
}, false)

Promise static method

1,Promise.resolve() quickly converts a value into a promise object.

2. If promise If resolve() passes in a promise object, the original path returns.

3. If the value passed in is an object and the object has a then method, it can be passed.

resolve
//The incoming promise object returns the original promise object
var promise = ajax('package.json')
var promise2 = Promise.resolve(promise)
console.log(promise === promise2) //true 

//The passed in object contains the then method, which can be obtained;
//You can pass in the promise Library of a third party, basically using the then method. You can turn the then of the third party library into a native promise
Promise.resolve({
    then(resolve, reject) {
        resolve('111')
    }
}).then((res) => {
    console.log(res)// '111'
})
reject

Quickly create a failed promise object. No matter what value is accepted, it is the reason for the failure

Promise.reject(new Error('123123')).then((res) => {
	console.log(res)
}).catch((err) => {
	console.log(err)
})

Promise.reject("12313").then((res) => {
	console.log(res)
}).catch((err) => {
	console.log(err)
})

Promise parallel processing

Promise.all()

If a request without interdependence is processed at the same time and multiple requests are requested at the same time, all requests will succeed only if they are successful, and an exception will result in failure.

 Promise_ajax('./api/all.json').then((res) => {
    const urlArr = Object.values(res)
    console.log(urlArr)
    const tasks = urlArr.map((url) => Promise_ajax(url))
    return Promise.all(tasks)
 }).then((res) => {
     console.log(res)
 })
Promie.race()

It depends on the result of the first result task. If the first successful result is true, it will be true. If one result fails, the last result will be failure

const prom = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(new Error('request was aborted'))
    }, 500)
})
Promise.race([
     Promise_ajax('./api/all.json'),
     prom
]).then((res) => {
    console.log(res)
})
Simulate poor request network

Promise execution timing
Macro task

setTimeout will be queued in the callback queue as a macro task. At present, most asynchronous calls are executed as macro tasks.

Micro task

Promise will be used as a micro task. When the current task ends, the micro task will be executed immediately without queuing at the end of the queue. Therefore, the callback of promise will be used as a micro task, which will be executed immediately after the end of the current round of call.

Promise summary

Promise provides chained call compared with traditional asynchronous call, which solves the problem of callback nesting

shortcoming

Promise's then can solve the problem of callback hell, but on the serial request, a then processes an asynchronous call, and finally forms an overall asynchronous task chain to realize serial execution; However, there will be a large number of callback functions written in this way. Although there is no nesting, it is not as readable as traditional code.

Generator function generator

describe

1. It's actually adding a * to the function declaration.

2. The Generator function Generator does not execute immediately, but returns a Generator function Generator object next() is executed step by step.

3. The function will execute the first time the Generator executes next.

4. yield does not end the function directly like return, but just pauses the function execution.

5. The yield keyword returns an object containing a value to the outside, and then pauses. The console behind the yield will not execute; The value attribute in the returned object is the result value of yield execution, and the done attribute is whether the execution status of the current function generator object has been completed.

characteristic

Let asynchronous calls return to flattening.

With the Generator, asynchronous code has the experience of synchronous code, but it will be troublesome to write an actuator function.

Basic grammar

function * fun() {
    console.log('Generator') 
    yield 'foo'; //Using the yield keyword, you can return a value outward, the first next (execution ends here)
    
    console.log('start 11')
    const res = yield 'start'; //The second next() execution ends here
    
    console.log("end")// The third next (execution ends here)
    console.log(res)
}

var generator = fun() //Does not execute immediately, and returns a Generator's function Generator object
console.log(generator) // Print Generator function Generator object
const reval = generator.next() //The body of the function will execute only when next() is called

//{value: "foo", done: false}
//Value is the value returned by yield; done is the execution status of the function generator and whether the current function generator has been fully executed.
console.log(reval) 

const reval2 = generator.next();
console.log(reval2) //{value: "start", done: false}

var he =generator.next("haha"); //The value passed in next will be displayed in the next
console.log(he) //{value: undefined, done: true}
Throw an exception inside the Generator function
function * fun (){
	console.log('Generator');
	try{
		let res = yield "foo";
		console.log(res)
	} catch (e){
		console.log(e)
	}
}
const gener = fun();
console.log(gener) //Returns the Generator object
console.log('---------')
console.log(gener.next()) //Print the Generator and return the value of yield {value: "foo", done: false}
console.log('---------')
console.log(gener.throw(new Error('Generator'))) //Get the exception value and return the value object and execution status of the last Generator

Continuous asynchronous

However, there are some problems with writing this way: Although handwritten code is readable in the request list, it is nested deeply in the callback, which is a bit like callback hell; Similar to the onion code.

function * fun() {
    try{
        const res1 = yield ajax('package.json');
        console.log(res1)
        const res2 = yield ajax('api/info.json');
        console.log(res2)
        const res3 = yield ajax('api/user.json')
        console.log(res3)
    } catch(err) {
        console.log(err)
    }
}
const gener = fun();

//Using nested methods
const gener1 = gener.next();
gener1.value.then((res) => {
    const gener2 = gener.next(res);
    gener2.value.then((res) => {
        const gener3 = gener.next(res);
        gener3.value.then((res) => {
            gener.next(res)
        })
    })
})

//Use recursion
function handleResult(result) {
    if(result.done) return;
    result.value.then((res) => {
        handleResult(gener.next(res))
    })
}
handleResult(gener.next())

//Then do exception handling on the basis of recursion, and add try catch above
function handleResult(result) {
    if(result.done) return;
    result.value.then((res) => {
        handleResult(gener.next(res))
    },(err) => {
        gener.throw(new Error(err))
    })
}
handleResult(gener.next())


//Encapsulate the above with higher-order functions. These methods were very popular before async and await came out, and the corresponding open source libraries also appeared: https://github.com/tj/co
function generatorFun(fun) {
    const generator = fun();

    function handleResult(result) {
        if(result.done) return;
        result.value.then((res) => {
            handleResult(generator.next(res))
        },(err) => {
            generator.throw(new Error(err))
        })
    }
    handleResult(generator.next())
}

generatorFun(fun)

async and await functions

describe

Use async and await to realize flattening. Async is a more convenient syntax sugar of the Generator function, and the syntax is somewhat similar.

Await must be executed in async functions, not in global or other functions that are not await

Difference between and Generator

async doesn't need a co Generator like Generator

Basic grammar

It is to remove the * of the Generator, add async in front of the ordinary function, and replace yield with await

async function fun(){
    try{
        const res1 = await ajax('package.json');
        console.log(res1)
        const res2 = await ajax('api/info.json');
        console.log(res2)
        const res3 = await ajax('api/user.json')
        console.log(res3)
    } catch(err) {
        console.log(err)
    }
}
fun()

be careful

The argument in then() must be a function. If it is not a function, ignore it

Take a look at the case:

1. 2 is a value. Ignore him.

2,Promise.resolve(3) is the promise object, ignoring it.

3. They will be replaced by Val = > Val, which is equivalent to promise resolve(1). then(val => val). then(val => val). then(console.log)

Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)

Use of HTML webpack plugin

If you don't want the node mode and want to use it in the browser, you don't need to start it once. This hot load, save and update is very convenient.

Use of HTML webpack plugin https://blog.csdn.net/qq_25286361/article/details/118121882

HTML webpack plugin https://blog.csdn.net/qq_25286361/article/details/118122912

Keywords: Javascript ECMAScript

Added by mfallon on Sun, 23 Jan 2022 02:35:44 +0200