Let's talk about the event loop model from setTimeout
As a developer who switched from other programming languages (C#/Java) to Javascript, in the process of learning Javascript, the operating principle of the setTimeout() method is a part that I encountered that is not easy to understand. This article attempts to combine it with other programming languages. The implementation, from the setTimeout event loop model
1. Let’s start with setTimeout
The setTimeout() method is not defined by the ecmascript specification, but is a function provided by the BOM. See w3school's definition of the setTimeout() method. The setTimeout() method is used to call a function or calculate an expression after a specified number of milliseconds.
Syntax setTimeout(fn, millisec), where fn represents the code to be executed, which can be a string containing JavaScript code or a function. The second parameter millisec is the time expressed in milliseconds, indicating how long fn needs to be delayed.
After calling the setTimeout() method, the method returns a number. This number is a unique identifier of the planned execution code, which can be used to cancel the timeout call.
At first, my use of setTimeout() was relatively simple, and I did not have a deep understanding of its operating mechanism until I saw the following code
var start = new Date; setTimeout(function(){ var end = new Date; console.log('Time elapsed:', end - start, 'ms'); }, 500); while (new Date - start < 1000) {};
In my initial understanding of setTimeout(), the delay was set to 500ms, so the output should be Time elapsed: 500 ms. Because in an intuitive understanding, the Javascript execution engine should be a sequential execution process from top to bottom when executing the above code, and the setTimeout function is executed before the while statement. But in fact, after the above code is run multiple times, the output is delayed by at least 1000ms.
2.Java’s implementation of setTimeout
Reminiscent of my past experience in learning Java, the above-mentioned setTimeout() of Javascript confused me. Java has multiple API implementations for setTimeout. Here we take the java.util.Timer package as an example. Use Timer to implement the above logic in Java. After running multiple times, the output is Time elapsed: 501 ms.
import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class TimerTest { public static void main(String[] args) { // TODO Auto-generated method stub long start = System.currentTimeMillis(); Timer timer = new Timer(); timer.schedule(new MyTask(start), 500); while (System.currentTimeMillis() - start < 1000) {}; } } class MyTask extends TimerTask { private long t; public MyTask(long start) { // TODO Auto-generated constructor stub t=start; } @Override public void run() { // TODO Auto-generated method stub long end = System.currentTimeMillis(); System.out.println("Time elapsed:"+(end - this.t)+ "ms"); } }
Before delving into why this difference occurs in setTimeout(), let’s first talk about the implementation principle of java.util.Timer.
The key elements of the above code are the Timer, TimerTask classes and the schedule method of the Timer class. You can understand its implementation by reading the relevant source code.
Timer: The scheduling class of a Task task. Like the TimerTask task, it is an API class for users to arrange the execution plan of the Task through the schedule method. This class completes Task scheduling through the TaskQueue task queue and TimerThread class.
TimerTask: Implements the Runnable interface, indicating that each task is an independent thread, and allows users to customize their own tasks through the run() method.
TimerThread: Inherited from Thread, it is the class that actually executes the Task.
TaskQueue: A data structure that stores Task tasks. It is internally implemented by a minimum heap. Each member of the heap is a TimeTask. Each task is sorted by the nextExecutionTime attribute value of TimerTask. The task with the smallest nextExecutionTime is at the front of the queue, so that the earliest implement.
3. Find the reasons based on the results
After looking at Java.util.Timer’s implementation of setTimeout(), let’s go back to the setTimeout() method of Javascript and see why the previous output does not match expectations.
var start = new Date; setTimeout(function(){ var end = new Date; console.log('Time elapsed:', end - start, 'ms'); }, 500); while (new Date - start < 1000) {};
It is not difficult to see by reading the code that the setTimeout() method is executed before the while() loop. It declares that it "hopes" to execute the anonymous function once after 500ms. This statement, that is, the registration of the anonymous function, is in the setTimeout() method. It takes effect immediately after execution. The while loop in the last line of the code will continue to run for 1000ms. The delay time of the output of the anonymous function registered through the setTimeout() method is always greater than 1000ms, indicating that the actual call to this anonymous function is blocked by the while() loop. The actual call is in The while() loop is actually executed after blocking.
In Java.util.Timer, the solution to scheduled tasks is implemented through multi-threading. The task object is stored in the task queue, and a dedicated scheduling thread completes the execution of the task in a new sub-thread. When registering an asynchronous task through the schedule() method, the scheduling thread immediately starts working in the child thread, and the main thread does not block the running of the task.
This is a major difference between Javascript and languages such as Java/C#, that is, the single-thread mechanism of Javascript. In the existing browser environment, the Javascript execution engine is single-threaded. The statements and methods of the main thread will block the running of scheduled tasks. The execution engine will only execute the scheduled tasks after executing the statements of the main thread. This is The period of time may be greater than the delay time set when registering the task. At this point, the mechanisms of Javascript and Java/C# are very different.
4.Event loop model
How does setTimeout() work in a single-threaded Javascript engine? Here we will mention the event loop model in the browser kernel. To put it simply, outside of the Javascript execution engine, there is a task queue. When the setTimeout() method is called in the code, the registered delay method will be handed over to other modules in the browser kernel (taking webkit as an example, it is the webcore module) Processing, when the delay method reaches the trigger condition, that is, when the set delay time is reached, this delay method is added to the task queue. This process is handled by other modules of the browser kernel and is independent of the main thread of the execution engine. After the execution of the main thread method is completed and the execution engine reaches the idle state, it will sequentially obtain tasks from the task queue for execution. This process is a continuous loop. The process is called the event loop model.
Referring to the information in a speech, the above event loop model can be described by the following figure.
When the main thread of the Javascript execution engine runs, a heap and stack are generated. The code in the program enters the stack one by one and waits for execution. When the setTimeout() method is called, that is, when the WebAPIs method on the right side of the figure is called, the corresponding module of the browser kernel starts processing the delay method. When the delay method reaches the trigger condition, the method is Added to the task queue for callback, as long as the code in the execution engine stack is executed, the main thread will read the task queue and execute those callback functions that meet the trigger conditions in sequence.
Use examples from the speech to further illustrate
Taking the code in the picture as an example, when the execution engine starts executing the above code, it is equivalent to adding a main() method to the execution stack. When continuing to start console.log('Hi'), the log('Hi') method is pushed onto the stack. The console.log method is a common method supported by the webkit kernel, not the method involved in WebAPIs in the previous figure, so log here ('Hi') method is immediately popped off the stack and executed by the engine.
After the console.log('Hi') statement is executed, the log() method is popped out of the stack and Hi is output. The engine continues down and adds setTimeout(callback,5000) to the execution stack. The setTimeout() method belongs to the method in WebAPIs in the event loop model. When the engine pops the setTimeout() method from the stack for execution, it hands over the delayed execution function to the corresponding module, that is, the timer module on the right side of the figure for processing.
When the execution engine pops setTimeout from the stack for execution, it hands over the delay processing method to the webkit timer module, and then immediately continues to process the following code, so log('SJS') is added to the execution stack, and then log('SJS' ) is executed out of the stack and SJS is output. After the execution engine executes console.log('SJS'), the program processing is completed and the main() method is also popped off the stack.
At this time, 5 seconds after the setTimeout method is executed, the timer module detects that the delay processing method reaches the trigger condition, so it adds the delay processing method to the task queue. At this time, the execution stack of the execution engine is empty, so the engine starts polling to check whether there are tasks in the task queue that need to be executed. It detects that the delay method has reached the execution condition, so it adds the delay method to the execution stack. The engine found that the delay method called the log() method, so it pushed the log() method onto the stack. Then the execution stack is popped out one after another, output there, and clear the execution stack.
After clearing the execution stack, the execution engine will continue to poll the task queue to check whether there are still tasks that can be executed.
5.webkit中timer的实现
到这里已经可以彻底理解下面代码的执行流程,执行引擎先将setTimeout()方法入栈被执行,执行时将延时方法交给内核相应模块处理。引擎继续处理后面代码,while语句将引擎阻塞了1秒,而在这过程中,内核timer模块在0.5秒时已将延时方法添加到任务队列,在引擎执行栈清空后,引擎将延时方法入栈并处理,最终输出的时间超过预期设置的时间。
var start = new Date; setTimeout(function(){ var end = new Date; console.log('Time elapsed:', end - start, 'ms'); }, 500); while (new Date - start < 1000) {};
前面事件循环模型图中提到的WebAPIs部分,提到了DOM事件,AJAX调用和setTimeout方法,图中简单的把它们总结为WebAPIs,而且他们同样都把回调函数添加到任务队列等待引擎执行。这是一个简化的描述,实际上浏览器内核对DOM事件、AJAX调用和setTimeout方法都有相应的模块来处理,webkit内核在Javasctipt执行引擎之外,有一个重要的模块是webcore模块,html的解析,css样式的计算等都由webcore实现。对于图中WebAPIs提到的三种API,webcore分别提供了DOM Binding、network、timer模块来处理底层实现,这里还是继续以setTimeout为例,看下timer模块的实现。
Timer类是webkit 内核的一个必需的基础组件,通过阅读源码可以全面理解其原理,本文对其简化,分析其执行流程。
通过setTimeout()方法注册的延时方法,被传递给webcore组件timer模块处理。timer中关键类为TheadTimers类,其包含两个重要成员,TimerHeap任务队列和SharedTimer方法调度类。延时方法被封装为timer对象,存储在TimerHeap中。和Java.util.Timer任务队列一样,TimerHeap同样采用最小堆的数据结构,以nextFireTime作为关键字排序。SharedTimer作为TimerHeap调度类,在timer对象到达触发条件时,通过浏览器平台相关的接口,将延时方法添加到事件循环模型中提到的任务队列中。
TimerHeap采用最小堆的数据结构,预期延时时间最小的任务最先被执行,同时,预期延时时间相同的两个任务,其执行顺序是按照注册的先后顺序执行。
var start = new Date; setTimeout(function(){ console.log('fn1'); }, 20); setTimeout(function(){ console.log('fn2'); }, 30); setTimeout(function(){ console.log('another fn2'); }, 30); setTimeout(function(){ console.log('fn3'); }, 10); console.log('start while'); while (new Date - start < 1000) {}; console.log('end while');
上述代码输出依次为
start while end while fn3 fn1 fn2 another fn2
参考资料
1.《Javascript异步编程》
2.JavaScript 运行机制详解:再谈Event Loophttp://www.ruanyifeng.com/blog/2014/10/event-loop.html
3.Philip Roberts: Help, I'm stuck in an event-loop.https://vimeo.com/96425312
4.How JavaScript Timers Work.http://ejohn.org/blog/how-javascript-timers-work/
5.How WebKit’s event model works.http://brrian.tumblr.com/post/13951629341/how-webkits-event-model-works
6.Timer实现.http://blog.csdn.net/shunzi__1984/article/details/6193023
The above is the detailed content of Let's talk about the event loop model from setTimeout. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Imagine an artificial intelligence model that not only has the ability to surpass traditional computing, but also achieves more efficient performance at a lower cost. This is not science fiction, DeepSeek-V2[1], the world’s most powerful open source MoE model is here. DeepSeek-V2 is a powerful mixture of experts (MoE) language model with the characteristics of economical training and efficient inference. It consists of 236B parameters, 21B of which are used to activate each marker. Compared with DeepSeek67B, DeepSeek-V2 has stronger performance, while saving 42.5% of training costs, reducing KV cache by 93.3%, and increasing the maximum generation throughput to 5.76 times. DeepSeek is a company exploring general artificial intelligence

AI is indeed changing mathematics. Recently, Tao Zhexuan, who has been paying close attention to this issue, forwarded the latest issue of "Bulletin of the American Mathematical Society" (Bulletin of the American Mathematical Society). Focusing on the topic "Will machines change mathematics?", many mathematicians expressed their opinions. The whole process was full of sparks, hardcore and exciting. The author has a strong lineup, including Fields Medal winner Akshay Venkatesh, Chinese mathematician Zheng Lejun, NYU computer scientist Ernest Davis and many other well-known scholars in the industry. The world of AI has changed dramatically. You know, many of these articles were submitted a year ago.

The performance of JAX, promoted by Google, has surpassed that of Pytorch and TensorFlow in recent benchmark tests, ranking first in 7 indicators. And the test was not done on the TPU with the best JAX performance. Although among developers, Pytorch is still more popular than Tensorflow. But in the future, perhaps more large models will be trained and run based on the JAX platform. Models Recently, the Keras team benchmarked three backends (TensorFlow, JAX, PyTorch) with the native PyTorch implementation and Keras2 with TensorFlow. First, they select a set of mainstream

Earlier this month, researchers from MIT and other institutions proposed a very promising alternative to MLP - KAN. KAN outperforms MLP in terms of accuracy and interpretability. And it can outperform MLP running with a larger number of parameters with a very small number of parameters. For example, the authors stated that they used KAN to reproduce DeepMind's results with a smaller network and a higher degree of automation. Specifically, DeepMind's MLP has about 300,000 parameters, while KAN only has about 200 parameters. KAN has a strong mathematical foundation like MLP. MLP is based on the universal approximation theorem, while KAN is based on the Kolmogorov-Arnold representation theorem. As shown in the figure below, KAN has

Boston Dynamics Atlas officially enters the era of electric robots! Yesterday, the hydraulic Atlas just "tearfully" withdrew from the stage of history. Today, Boston Dynamics announced that the electric Atlas is on the job. It seems that in the field of commercial humanoid robots, Boston Dynamics is determined to compete with Tesla. After the new video was released, it had already been viewed by more than one million people in just ten hours. The old people leave and new roles appear. This is a historical necessity. There is no doubt that this year is the explosive year of humanoid robots. Netizens commented: The advancement of robots has made this year's opening ceremony look like a human, and the degree of freedom is far greater than that of humans. But is this really not a horror movie? At the beginning of the video, Atlas is lying calmly on the ground, seemingly on his back. What follows is jaw-dropping

Today I would like to share a recent research work from the University of Connecticut that proposes a method to align time series data with large natural language processing (NLP) models on the latent space to improve the performance of time series forecasting. The key to this method is to use latent spatial hints (prompts) to enhance the accuracy of time series predictions. Paper title: S2IP-LLM: SemanticSpaceInformedPromptLearningwithLLMforTimeSeriesForecasting Download address: https://arxiv.org/pdf/2403.05798v1.pdf 1. Large problem background model

The latest video of Tesla's robot Optimus is released, and it can already work in the factory. At normal speed, it sorts batteries (Tesla's 4680 batteries) like this: The official also released what it looks like at 20x speed - on a small "workstation", picking and picking and picking: This time it is released One of the highlights of the video is that Optimus completes this work in the factory, completely autonomously, without human intervention throughout the process. And from the perspective of Optimus, it can also pick up and place the crooked battery, focusing on automatic error correction: Regarding Optimus's hand, NVIDIA scientist Jim Fan gave a high evaluation: Optimus's hand is the world's five-fingered robot. One of the most dexterous. Its hands are not only tactile

This paper explores the problem of accurately detecting objects from different viewing angles (such as perspective and bird's-eye view) in autonomous driving, especially how to effectively transform features from perspective (PV) to bird's-eye view (BEV) space. Transformation is implemented via the Visual Transformation (VT) module. Existing methods are broadly divided into two strategies: 2D to 3D and 3D to 2D conversion. 2D-to-3D methods improve dense 2D features by predicting depth probabilities, but the inherent uncertainty of depth predictions, especially in distant regions, may introduce inaccuracies. While 3D to 2D methods usually use 3D queries to sample 2D features and learn the attention weights of the correspondence between 3D and 2D features through a Transformer, which increases the computational and deployment time.
