Timer
setTimeout
is what we often use. It is used to call a function or calculate an expression after a specified number of milliseconds.
Syntax:
setTimeout(code, millisec, args);
Note: If the code is a string, it is equivalent to executing the
eval()
method to execute the code.
Of course, this article not only tells you how to use
setTimeout
, but also understands how it is executed.
Let’s look at a piece of code first:
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {}
In the above code, a
setTimeout
Timer, the delay time is 500 milliseconds.
Do you think the print result is: 500
But the fact is that it is beyond your expectation. The print result is like this (maybe it will be different when you print it out, but it will definitely be greater than 1000 Milliseconds):
#Why is this? The reason is that JavaScript is executed in a single thread. In other words, at any point in time, there is and is only one thread running the JavaScript program, and multiple pieces of code cannot be run at the same time.
Let’s take a look at JavaScript under the browser.
The kernel of the browser is multi-threaded. They cooperate with each other under the control of the kernel to maintain synchronization. A browser implements at least three resident threads: JavaScript engine thread, GUI rendering thread, and browser event triggering thread. .
JavaScript引擎
is based on event-driven single-thread execution. The JavaScript engine has been waiting for the arrival of tasks in the task queue and then processed them. The browser has only one JavaScript thread running at any time. JavaScript program.
GUI渲染线程
is responsible for rendering the browser interface. This thread will be executed when the interface needs to be repainted (Repaint) or when a reflow (Reflow) is caused by some operation. However, it should be noted that the GUI rendering thread and the JavaScript engine are mutually exclusive. When the JavaScript engine is executed, the GUI thread will be suspended, and GUI updates will be saved in a queue and will be executed immediately when the JavaScript engine is idle.
事件触发线程
, when an event is triggered, the thread will add the event to the end of the pending queue and wait for processing by the JavaScript 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 JavaScript, all these events have to be queued to wait for processing by the JavaScript engine. (Asynchronous code will be executed only when no synchronous code is executed in the thread).
Here, let’s review the original example:
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {}
Although the delay time of
setTimeout
is 500 milliseconds, Due to the existence of the
while
loop, the while loop will only jump out when the interval is greater than 1000 milliseconds. That is to say, before 1000 milliseconds, the while loop is occupying the JavaScript thread. In other words, only after waiting to jump out of while, the thread will become idle and execute the previously defined setTimeout.
Finally, we can conclude that
setTimeout
can only guarantee that the task (function that needs to be executed) will be inserted into the task queue to wait after the specified time, but it does not guarantee when the task will be executed. implement. Once the thread executing javascript is free, remove the task from the queue and execute it.
Because the JavaScript thread is not blocked due to any time-consuming operations, it can quickly take out the tasks in the queue and execute it. It is also this queue mechanism that creates the illusion of asynchronous execution for us.
Maybe you have seen the following code:
setTimeout(function(){ // statement}, 0);
The above code means immediate execution. The original intention is to execute the calling function immediately, but in fact, the above code is not executed immediately. This is because setTimeout has a minimum execution time. When the specified time is less than that time, the browser will use the minimum allowed time as setTimeout. time interval, that is to say, even if we set the delay time of setTimeout to 0, the called program does not start immediately.
The actual situation of different browsers is different. The time accuracy of IE8 and earlier IE is 15.6ms. However, with the emergence of HTML5, in advanced versions of browsers (Chrome, IE9+, etc.), the minimum time interval defined is not less than 4 milliseconds. If it is lower than this value, it will automatically increase, and in 2010 and later Adopted consistently across published browsers.
So, when we write
setTimeout(fn,0)
, we are actually implementing the queue jumping operation, requiring the browser to perform the callback "as quickly as possible", but how fast can it actually be? It all depends on the browser.
What is the use of
setTimeout(fn, 0)
? In fact, the utility lies in that we can change the order of task execution! Because the browser will execute the tasks accumulated in the setTimeout queue after completing the tasks in the current task queue.
By setting the task to be executed after delaying to 0s, you can change the order of task execution, delay the occurrence of the task, and make it execute asynchronously.
Let’s look at a very popular example on the Internet:
document.querySelector('#one input').onkeydown = function() { document.querySelector('#one span').innerHTML = this.value; }; document.querySelector('#second input').onkeydown = function() { setTimeout(function() { document.querySelector('#second span').innerHTML = document.querySelector('#second input').value; }, 0); };
`实例:实例
当你往两个表单输入内容时,你会发现未使用setTimeout函数的只会获取到输入前的内容,而使用setTimeout函数的则会获取到输入的内容。
这是为什么呢?
因为当按下按键的时候,JavaScript 引擎需要执行 keydown 的事件处理程序,然后更新文本框的 value 值,这两个任务也需要按顺序来,事件处理程序执行时,更新 value值(是在keypress后)的任务则进入队列等待,所以我们在 keydown 的事件处理程序里是无法得到更新后的value的,而利用 setTimeout(fn, 0),我们把取 value 的操作放入队列,放在更新 value 值以后,这样便可获取出文本框的值。
未使用setTimeout函数,执行顺序是:`onkeydown => onkeypress => onkeyup
使用setTimeout函数,执行顺序是:
onkeydown => onkeypress => function => onkeyup`
虽然我们可以使用
keyup
来替代
keydown
,不过有一些问题,那就是长按时,
keyup
并不会触发。
长按时,keydown、keypress、keyup的调用顺序:
keydown keypress keydown keypress ... keyup
也就是说keyup只会触发一次,所以你无法用keyup来实时获取值。
我们还可以用
setImmediate()
来替代
setTimeout(fn,0)
:
if (!window.setImmediate) { window.setImmediate = function(func, args){ return window.setTimeout(func, 0, args); }; window.clearImmediate = window.clearTimeout; }
setImmediate()`方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数,必选的第一个参数func,表示将要执行的回调函数,它并不需要时间参数。
注意:目前只有IE10支持此方法,当然,在Nodejs中也可以调用此方法。
3.1 setTimeout中回调函数的this
由于setTimeout() 方法是浏览器 window 对象提供的,因此第一个参数函数中的this其实是指向window对象,这跟变量的作用域有关。
看个例子:
var a = 1; var obj = { a: 2, test: function() { setTimeout(function(){ console.log(this.a); }, 0); } }; obj.test(); // 1
不过我们可以通过使用bind()方法来改变setTimeout回调函数里的this
var a = 1; var obj = { a: 2, test: function() { setTimeout(function(){ console.log(this.a); }.bind(this), 0); } }; obj.test(); // 2
3.2 setTimeout不止两个参数
我们都知道,setTimeout的第一个参数是要执行的回调函数,第二个参数是延迟时间(如果省略,会由浏览器自动设置。在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。)
其实,setTimeout可以传入第三个参数、第四个参数….,它们表示神马呢?其实是用来表示第一个参数(回调函数)传入的参数。
setTimeout(function(a, b){ console.log(a); // 3 console.log(b); // 4},0, 3, 4);
以上就是JavaScript 开发者应该知道的 setTimeout 秘密 的内容,更多相关内容请关注PHP中文网(www.php.cn)!