Analysis of JS asynchronous execution mechanism

foreword

JS asynchronous execution mechanism has a very important position, especially in callback functions and events. This article will conduct a simple analysis of the JS asynchronous execution mechanism.

Start with a code

The following are two classic JS timing execution functions. The difference between these two functions is believed to be very clear to students who have a certain foundation in JS. timeout will only be executed once, while interval will be executed multiple times.

    setTimeout(function (args) {
        console.log('timeout')
    }, 1000);
    setInterval(function (args) {
        console.log('interval')
    }, 1000);

Then look at another code

    setTimeout(function (args) {
        console.log('timeout');
        setTimeout(arguments.callee, 1000);
    }, 1000);
    setInterval(function (args) {
        console.log('interval')
    }, 1000);

Is there a difference between the two codes? The recursive call in setTimeout seems to be the same as setInterval, but in fact, due to the problem of JS asynchronous execution mechanism, there are certain differences between these two functions.

How to understand JS asynchronous execution mechanism

JS is a single-threaded program, thus avoiding a series of problems with concurrent access. But it is also because of the single-threaded mechanism that the asynchronous execution of JS cannot be executed asynchronously according to the traditional multi-threaded method. All asynchronous time must be inserted into the same queue and executed in the main thread in turn.
2018-04-29-14-28-40
Here is a picture that can better explain the asynchronous execution mechanism of JS.
In the browser, there are generally three threads, the JS execution engine, the HTTP thread, and the event trigger thread. But it should be noted that all JS core logic needs to be executed in the JS execution engine thread.
For example, we can use the following code to send an AJAX request

    var xmlReq = createXMLHTTP();//创建一个xmlhttprequest对象
    function testAsynRequest() {
        var url = "http://127.0.0.1:5000/";
        xmlReq.open("post", url, true);
        xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlReq.onreadystatechange = function () {
            if (xmlReq.readyState == 4) {
                if (xmlReq.status == 200) {
                    var jsonData = eval('(' + xmlReq.responseText + ')');
                    alert(jsonData.message);
                }
                else if (xmlReq.status == 404) {
                    alert("Requested URL is not found.");
                } else if (xmlReq.status == 403) {
                    alert("Access denied.");
                } else {
                    alert("status is " + xmlReq.status);
                }
            }
        };
        xmlReq.send(null);
    }
    testAsynRequest();//1秒后调用回调函数
    while (true) {

    }

server code

from flask import Flask

app = Flask(__name__)

@app.route('/', methods=['POST', 'GET'])
def print():
    return 'hello world'
if __name__ == '__main__':
    app.run()

Will this code output hello world? After testing, it is found that HelloWorld will not be output, and the browser will enter a suspended animation state. The reason for this is the single-threaded running mechanism of JS asynchronous callbacks. After sending the HTTP request, the HTTP request will start a thread to send it. After receiving the response, the event triggering thread will add the response event to the waiting queue and execute it after waiting for the JS engine to be idle.
However, due to while(true), the JS engine will never be idle, so that the response events cannot be triggered consistently.

rethink

Through a simple AJAX DEMO, you can simply understand a process of JS time execution. So how does JS schedule and process the above picture and the settimeout question raised at the beginning?
After the timer function is initialized, JS will start to execute the timed task. After the time is reached, if the JS engine is idle at this time, the timed task will be executed directly, otherwise the timed task will be added to the waiting queue.
For tasks added to the waiting queue, they will be executed continuously when the JS engine is idle. Therefore, if the engine is not idle at this time, setTimeout will wait for a while before executing.
For setInterval, it also needs to be added to the waiting queue, but setInterval will not stop timing because it is added to the waiting queue. At this time, if the second Interval arrives and the first Interval has not started to execute, then this At the time, there were two Intervals in the queue. If the accumulation continues, it may fall into the accumulation of a large number of Intervals, causing serious thread blocking. Therefore, the JS engine has made a slight optimization . If there are Intervals in the queue, Then this Interval will not be added to the queue. But if the Interval has been popped out of the queue to start executing, then the Interval will be added to the queue.
Based on the above analysis, we can draw a conclusion that compared with the recursive call of the setTimeout function, in JS, due to the single-threaded asynchronous execution mechanism, the frequency of setInterval execution will be higher . Because setTimeout starts the next round of timing tasks after the execution is completed, but setInterval continuously executes timing tasks, especially when the tasks in setTimeout take a long time to execute, setInterval and setTimeout will have a relatively obvious frequency difference.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325059447&siteId=291194637