Home  >  Article  >  Web Front-end  >  Introduction to JavaScript single-thread mechanism and setTimeout execution principle (with code)

Introduction to JavaScript single-thread mechanism and setTimeout execution principle (with code)

不言
不言forward
2019-03-27 09:09:013361browse

This article brings you an introduction to the JavaScript single-thread mechanism and setTimeout execution principle (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Javascript engine single-threaded mechanism

First of all, it is clear that the JavaScript engine is a single-threaded mechanism.

JavaScript is executed in a single thread and cannot execute multiple pieces of code at the same time. When a certain piece of code is executing, all subsequent tasks must wait, forming a task queue. Once the current task is executed, the next task is taken out of the queue, which is often called "blocking execution".

It can be understood as: asynchronous code will be executed only if there is no synchronous code to be executed in the JS thread

So a mouse click, or the timer reaches the time point, or the Ajax request is completed When a callback function is triggered, these event handlers or callback functions will not run immediately, but will be queued immediately and executed once the thread is free. If the current JavaScript thread is executing a time-consuming code and a mouse click occurs, the event handler will be blocked and the user will not be able to see the feedback immediately. The event handler will be put into the task queue until the previous Execution will not begin until the code ends. If a setTimeout is set in the code, the browser will insert the code into the task queue at the appropriate time. If this time is set to 0, it means that it will be inserted into the queue immediately, but it will not be executed immediately. You will still have to wait for the previous code to be executed. . Therefore, setTimeout does not guarantee the execution time. Whether it is executed in time depends on whether the JavaScript thread is crowded or idle.

Browser's multi-threading mechanism and event loop

First of all, it is clear that the browser's kernel is multi-threaded. They cooperate with each other under the control of the kernel to maintain synchronization. A browser must at least Implement three resident threads:

javascript engine thread

GUI rendering thread

Browser event trigger thread

JavaScript engine is single-threaded Running, the browser has only one thread running the JavaScript program at any time

javascript engine is based on event-driven single-thread execution. The JS engine has been waiting for the arrival of tasks in the task queue, and then adds Processing, the browser has only one JS thread running the JS program at any time.

The GUI rendering thread is responsible for rendering the browser interface. This thread will be executed when the interface needs to be repainted (Repaint) or when a reflow is caused by some operation. However, it should be noted that the GUI rendering thread and the JS engine are mutually exclusive. When the JS engine is executed, the GUI thread will be suspended, and GUI updates will be saved in a queue and executed immediately when the JS engine is idle.

Event trigger thread. When an event is triggered, the thread will add the event to the end of the pending queue and wait for processing by the JS engine. These events can come from the code block currently executed by the JavaScript engine such as setTimeOut, or from other threads in the browser kernel such as mouse clicks, AJAX asynchronous requests, etc. However, due to the single-threaded relationship of JS, all these events have to be queued for processing by the JS engine. (Asynchronous code will be executed when no synchronous code is executed in the thread)

Event loop (event loop): is used to manage our asynchronous code, it will put them in a thread pool Among them

The implementation principle of setTimeout in JavaScript

First of all, it is clear that the setTimeout function is an asynchronous code, but in fact setTimeout is not a true asynchronous operation

Due to the working mechanism of the JS thread: Asynchronous code will only be executed when no synchronous code is executed in the thread. setTimeout is an asynchronous code, so setTimeout can only be executed when js is idle

As mentioned earlier, if a is set in the code setTimeout, then the browser will insert the code into the task queue at the appropriate time. If this time is set to 0, it means that it will be inserted into the queue immediately, but it will not be executed immediately. It will still have to wait for the previous code to be executed. Therefore, setTimeout does not guarantee the execution time. Whether it is executed in time depends on whether the JavaScript thread is crowded or idle.

That is to say, setTimeout can only guarantee that the task (function that needs to be executed) will be inserted into the queue to wait after the specified time. It does not guarantee when the task will be executed. The thread executing JavaScript will take out the task from the queue and execute it when it is idle. JavaScript uses this queue mechanism to give us the illusion of asynchronous execution.

Sometimes the code in setTimeout will be executed quickly, and we will feel that this code is executed asynchronously. This is because the JavaScript thread is not blocked due to any time-consuming operations, so it can be quickly removed from the queue. The task in the queue is then executed.

Example analysis

After having the above theoretical basis, we analyze the following examples:

======= ====================================

var t = true;
    
window.setTimeout(function (){
    t = false;
},1000);
    
while (t){}
    
alert('end');

Running result: The program falls into an infinite loop , t = false will not be executed, so alert('end') will not be executed.
Analysis:

JS是单线程的,所以会先执行 while(t){} 再 alert,但这个循环体是死循环,所以永远不会执行alert。

为什么不执行 setTimeout?是因为JS的工作机制是:当线程中没有执行任何同步代码的前提下才会执行异步代码,setTimeout是异步代码,所以 setTimeout 只能等JS空闲才会执行,但死循环是永远不会空闲的,所以 setTimeout 也永远得不到执行。

===========================================

var start = new Date();
    
setTimeout(function(){  
    var end = new Date();  
    console.log("Time elapsed: ", end - start, "ms");  
}, 500);  
      
while (new Date - start <= 1000){}

运行结果:"Time elapsed: 1035 ms" (这里的1035不准确 但是一定是大于1000的)
解析:

JS是单线程 setTimeout 异步代码 其回调函数执行必须需等待主线程运行完毕

当while循环因为时间差超过 1000ms 跳出循环后,setTimeout 函数中的回调才得以执行

===========================================

for(var i=0;i<10;i++){
    setTimeout(function() {
        console.log(i);
    }, 0);
}

运行结果:输出10个10
解析:JS单线程 setTimeout 异步代码 任务队列
问:如何修改可以使上述代码输出 0123456789
自执行函数 或 使用ES6中的let关键字

// 自执行函数 形成闭包 记忆其被创建时的环境
for(var i=0;i<10;i++){
    setTimeout((function() {
         console.log(i);
    })(), 0);
}

setTimeout(0)函数的作用

现在我们了解了setTimeout函数执行的原理,那么它有什么作用呢?
setTimeout函数增加了Javascript函数调用的灵活性,为函数执行顺序的调度提供极大便利。
简言之,改变顺序,这正是setTimeout(0)的作用。

使用场景示例:

<input type="text" onkeydown="show(this.value)">  
<p></p>  
<script type="text/javascript">  
  function show(val) {  
    document.getElementsByTagName('p')[0].innerHTML = val;  
  }  
</script>

这里绑定了 keydown 事件,意图是当用户在文本框里输入字符时,将输入的内容实时地在

中显示出来。但是实际效果并非如此,可以发现,每按下一个字符时,

中只能显示出之前的内容,无法得到当前的字符。

修改代码:

  <input type="text" onkeydown="var self=this; setTimeout(function(){show(self.value)}, 0)">  
  <p></p>  
  <script type="text/javascript">  
    function show(val) {  
      document.getElementsByTagName('p')[0].innerHTML = val;  
    }  
  </script>

这段代码使用setTimeout(0)就可以实现需要的效果了。

这里其实涉及2个任务,1个是将键盘输入的字符回写到输入框中,一个是获取文本框的值将其写入p中。第一个是浏览器自身的默认行为,一个是我们自己编写的代码。很显然,必须要先让浏览器将字符回写到文本框,然后我们才能获取其内容写到p中。改变顺序,这正是setTimeout(0)的作用。

其他应用场景:有时候,加载一些广告的时候,我们用setTimeout实现异步,好让广告不会阻塞我们页面的渲染。

setTimeout 和 setInterval 在执行异步代码的时候有着根本的不同

如果一个计时器被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些)

如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!

The above is the detailed content of Introduction to JavaScript single-thread mechanism and setTimeout execution principle (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete