js_ Speculation on the action of setTimeout, JS single thread task queue and let/var declared loop variables

Posted by sobbayi on Thu, 07 Oct 2021 04:50:47 +0200

declaration

This is a beginner's guess

Test code

The running environment is vscode+code runner

Code description

To explore the execution of setTimeout()
I added a timestamp when the setTimeout() task was executed for reference
If necessary, you can add a timestamp print statement in the appropriate place to test
Generally, you only need to see the difference between the last 5 digits / 4 digits

It includes the test of the task execution queue of a series of tasks arranged by the setTimeout() function
It should explain some phenomena (and verify some of my guesses)

// let cnt=0;
for (var i = 0; i < 5; ++i) {
    // Probably because js is single threaded
    //Statements other than setTimeout() take precedence
    //The task scheduled by setTimeout() will be added to the js task queue (the time of adding depends on the timeout parameter), and the execution time of the task in the queue depends on whether the task is the first task in the queue
    setTimeout(() => console.log("for1:test insert to the task queue" + ' timeout==0'), 0);
    const id = setTimeout(() => console.log(i+"\tby setTimeout_handler"+ ' timestamp='+ +new Date()), 2000);//id debug monitor due to breakpoint
    // cnt++;
    console.log(i + " \n\t(var:output by single console.log() after the setTimeout())");
    if (i==4){
        console.log("now i===4,the timestamp: "+ +new Date());
    }
}
console.log("---------------------------------------------------------");
setTimeout(()=>console.log("the outer setTimeout(),test first to the task queue by setTimeout():timeout=0ms"),0);
setTimeout(()=>console.log("seperate two for_setTimeout():timeout=2s"),2000);
setTimeout(()=>console.log("end for_setTimeout():timeout=2.1s"),2100);

for (let i = 0; i < 5; ++i) {
    // It may be because js is single threaded, and setTimeout can be executed only after the for execution is completed
    //Add to js task queue
    setTimeout(() => console.log("for2:test insert to the task queue" + i + ' timeout==0'), 0);
    // const id_start = setTimeout(() => console.log("setTimeout in the second for ."), 2000);
    const id = setTimeout(() => console.log(2 * i), 2000);
    console.log(i + " \n\t(let:output by single console.log() after the setTimeout())");
}
console.log("the last statement(in outer context(relative to setTimeout() task queue)):over time stamp :"+ +new Date());
/* Because the number of cycles is very small, it can almost be considered that the execution time of the for loop is close to 0s
 First of all, it should be understood that task scheduling is different from task insertion and execution. When understanding task scheduling, ignore the timeout parameter of setTimeout() and the task function (called handler) passed to setTimeout(). Timeout is reflected in delaying the insertion of tasks into the queue (after setTimeout arranges the handler, it starts to count down the timeout and insert it into the task queue at the end of the timing. Until now, it is not clear what the handler wants to do (or whether it will use the variable I in the circular variable for)) In addition, although the handler cannot confirm that it will execute immediately after entering the task queue, if it has a task before it, it will have to wait again. This time is uncertain

(for Tasks that are not arranged by the timer function seem to be different from the queue tasks generated by the timer function, and have priority to be executed.) the handler has to wait until these statements are completed before execution). When the tasks enter the execution queue, they will be executed one by one
 setTimeout() sets the delay (inserted into the task execution queue) through the timeout parameter
 Here, the for loop will be executed five times, and the insertion queue operation of the setTimeout task will end with the end of for
 If the timeout parameter of setTimeout() you set in for is 0ms, once the for task ends, the tasks specified in setTimeout() will be arranged together. After the for execution ends, the remaining tasks in the task queue (arranged through setTimeout()) will be executed immediately. After the task is inserted, the time of the timeout parameter in the corresponding setTimeout() will not be used up, We still take the timeout of 0ms as an example. In this example, these tasks (printing) can be completed very quickly. Therefore, the phenomenon is that five 5S will be printed almost at the same time (of course, the output will start after the end of for) (you can see it if you use vscode) (the browser will give a simplified output of 5 * 5)*/

Code experiment results

❯ node "d:\repos\web\Web\04-JavaScript_basic\var_settimeout.js"
0 
        (var:output by single console.log() after the setTimeout())
1 
        (var:output by single console.log() after the setTimeout())
2
        (var:output by single console.log() after the setTimeout())
3
        (var:output by single console.log() after the setTimeout())
4
        (var:output by single console.log() after the setTimeout())
now i===4,the timestamp: 1633488870677
---------------------------------------------------------
0
        (let:output by single console.log() after the setTimeout())
1
        (let:output by single console.log() after the setTimeout())
2
        (let:output by single console.log() after the setTimeout())
3
        (let:output by single console.log() after the setTimeout())
4
        (let:output by single console.log() after the setTimeout())
the last statement(in outer context(relative to setTimeout() task queue)):over time stamp :1633488870684
for1:test insert to the task queue timeout==0
for1:test insert to the task queue timeout==0
for1:test insert to the task queue timeout==0
for1:test insert to the task queue timeout==0
for1:test insert to the task queue timeout==0
the outer setTimeout(),test first to the task queue by setTimeout():timeout=0ms
for2:test insert to the task queue0 timeout==0
for2:test insert to the task queue1 timeout==0
for2:test insert to the task queue2 timeout==0
for2:test insert to the task queue3 timeout==0
for2:test insert to the task queue4 timeout==0
5       by setTimeout_handler timestamp=1633488872659
5       by setTimeout_handler timestamp=1633488872679
5       by setTimeout_handler timestamp=1633488872680
5       by setTimeout_handler timestamp=1633488872682
5       by setTimeout_handler timestamp=1633488872683
seperate two for_setTimeout():timeout=2s
0
2
4
6
8
end for_setTimeout():timeout=2.1s

Conclusion?

Well, it's almost fun not to give a conclusion

First of all, it should be understood that task arrangement is different from task insertion and execution. When understanding task arrangement, ignore the timeout parameter of setTimeout() (and the task function (called handler) passed to setTimeout()),

Timeout is reflected in delaying the insertion of tasks into the queue (after setTimeout arranges the handler, it starts to count down the timeout and insert it into the task queue at the end of the timing. However, until now, it is not clear what the handler is going to do (or whether it will use the variable I in the circular variable for)),

In addition, although the handler cannot confirm that it will execute immediately after entering the task queue,
If it has a task before it, it has to wait again. The time is uncertain. (according to the time of the task before it)

(in this example, tasks such as for that are not arranged by the timer function seem to be different from queue tasks generated by the timer function. They have the phenomenon of priority execution. From the print log I designed, this is the case.)
the last statement(in outer context(relative to setTimeout() task queue)):over time stamp :1633488870684
This output appears before the output generated by other handler s

The handler has to wait until these statements are completed), and the tasks will be executed one by one after entering the execution queue
setTimeout() sets the delay (inserted into the task execution queue) through the timeout parameter
Here, the for loop will be executed five times, and the scheduling of the setTimeout task (instead of inserting the queue, the insertion depends on the timeout value) will end with the end of for

If the timeout parameter of setTimeout() you set in for is 0ms, once the for task ends, the tasks specified in setTimeout() will be arranged together. After the for execution ends, the tasks in the task queue (arranged through setTimeout()) will be executed immediately. When the corresponding timeout time comes, the task will be inserted and the corresponding setTimeout() The time of the timeout parameter in is not used up,
We still take the timeout of 0ms as an example. In this example, these tasks (printing) can be completed very quickly. Therefore, the phenomenon is that five 5 will be printed almost at the same time (of course, the output will start after the end of for) (you can see it if you use vscode) (the browser will give a simplified output of 55)/

Topics: Javascript node.js