search
HomeWeb Front-endJS TutorialLet'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(&#39;Time elapsed:&#39;, end - start, &#39;ms&#39;);
}, 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

Lets talk about the event loop model from setTimeout

Lets talk about the event loop model from setTimeout

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.

Lets talk about the event loop model from setTimeout

Lets talk about the event loop model from setTimeout

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.

Lets talk about the event loop model from setTimeout

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.

Lets talk about the event loop model from setTimeout

Lets talk about the event loop model from setTimeout

Lets talk about the event loop model from setTimeout

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(&#39;Time elapsed:&#39;, end - start, &#39;ms&#39;);
}, 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 内核的一个必需的基础组件,通过阅读源码可以全面理解其原理,本文对其简化,分析其执行流程。

Lets talk about the event loop model from setTimeout

  通过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(&#39;fn1&#39;);
}, 20);
setTimeout(function(){
console.log(&#39;fn2&#39;);
}, 30);
setTimeout(function(){
console.log(&#39;another fn2&#39;);
}, 30);
setTimeout(function(){
console.log(&#39;fn3&#39;);
}, 10);
console.log(&#39;start while&#39;);
while (new Date - start < 1000) {};
console.log(&#39;end while&#39;);

  上述代码输出依次为

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!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
JavaScript's Core: Is It Built on C or C  ?JavaScript's Core: Is It Built on C or C ?May 05, 2025 am 12:07 AM

JavaScriptisnotbuiltonCorC ;it'saninterpretedlanguagethatrunsonenginesoftenwritteninC .1)JavaScriptwasdesignedasalightweight,interpretedlanguageforwebbrowsers.2)EnginesevolvedfromsimpleinterpreterstoJITcompilers,typicallyinC ,improvingperformance.

JavaScript Applications: From Front-End to Back-EndJavaScript Applications: From Front-End to Back-EndMay 04, 2025 am 12:12 AM

JavaScript can be used for front-end and back-end development. The front-end enhances the user experience through DOM operations, and the back-end handles server tasks through Node.js. 1. Front-end example: Change the content of the web page text. 2. Backend example: Create a Node.js server.

Python vs. JavaScript: Which Language Should You Learn?Python vs. JavaScript: Which Language Should You Learn?May 03, 2025 am 12:10 AM

Choosing Python or JavaScript should be based on career development, learning curve and ecosystem: 1) Career development: Python is suitable for data science and back-end development, while JavaScript is suitable for front-end and full-stack development. 2) Learning curve: Python syntax is concise and suitable for beginners; JavaScript syntax is flexible. 3) Ecosystem: Python has rich scientific computing libraries, and JavaScript has a powerful front-end framework.

JavaScript Frameworks: Powering Modern Web DevelopmentJavaScript Frameworks: Powering Modern Web DevelopmentMay 02, 2025 am 12:04 AM

The power of the JavaScript framework lies in simplifying development, improving user experience and application performance. When choosing a framework, consider: 1. Project size and complexity, 2. Team experience, 3. Ecosystem and community support.

The Relationship Between JavaScript, C  , and BrowsersThe Relationship Between JavaScript, C , and BrowsersMay 01, 2025 am 12:06 AM

Introduction I know you may find it strange, what exactly does JavaScript, C and browser have to do? They seem to be unrelated, but in fact, they play a very important role in modern web development. Today we will discuss the close connection between these three. Through this article, you will learn how JavaScript runs in the browser, the role of C in the browser engine, and how they work together to drive rendering and interaction of web pages. We all know the relationship between JavaScript and browser. JavaScript is the core language of front-end development. It runs directly in the browser, making web pages vivid and interesting. Have you ever wondered why JavaScr

Node.js Streams with TypeScriptNode.js Streams with TypeScriptApr 30, 2025 am 08:22 AM

Node.js excels at efficient I/O, largely thanks to streams. Streams process data incrementally, avoiding memory overload—ideal for large files, network tasks, and real-time applications. Combining streams with TypeScript's type safety creates a powe

Python vs. JavaScript: Performance and Efficiency ConsiderationsPython vs. JavaScript: Performance and Efficiency ConsiderationsApr 30, 2025 am 12:08 AM

The differences in performance and efficiency between Python and JavaScript are mainly reflected in: 1) As an interpreted language, Python runs slowly but has high development efficiency and is suitable for rapid prototype development; 2) JavaScript is limited to single thread in the browser, but multi-threading and asynchronous I/O can be used to improve performance in Node.js, and both have advantages in actual projects.

The Origins of JavaScript: Exploring Its Implementation LanguageThe Origins of JavaScript: Exploring Its Implementation LanguageApr 29, 2025 am 12:51 AM

JavaScript originated in 1995 and was created by Brandon Ike, and realized the language into C. 1.C language provides high performance and system-level programming capabilities for JavaScript. 2. JavaScript's memory management and performance optimization rely on C language. 3. The cross-platform feature of C language helps JavaScript run efficiently on different operating systems.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

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

Hot Tools

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft