After reading this article, 1. Note whether setTimeout references all variables or local variables. When the external function method is called directly, the internal variables of the function have actually become global. 2. Remind me to prevent errors. Using anonymous functions is not prone to errors. 3. The fastest execution time of setTimeout is 4 ms. 4. The setTimeout function is slower than the function in the current queue. 5. The timer in setTimeout is not an accurate time. In reality, it needs to be scheduled only after the previous function is executed.
For more information about setTimeout, see
Javascript provides the function of regularly executing code, called the timer, which is mainly completed by the setTimeout () and setInterval () functions. They add scheduled tasks to the task queue. People who initially came into contact with it thought it was easy. Is it true in real time? Here we will record the process of using posture changes along the way.
1. setTimeout () basics
The setTimeout function is used to specify the number of milliseconds after a function or code segment. It returns an integer indicating the timer number, which can be used to cancel the timer later.
Var timerId = setTimeout (func | code, delay)
In the code above, the setTimeout function accepts two parameters. The first parameter func | code is the name of the function to be postponed or a piece of code, and the second parameter delay is the number of milliseconds to postpone execution.
Console. log (1 );
SetTimeout ('console. log (2) ', 1000 );
Console. log (3 );
The output result of the above code is 1000, 2, because setTimeout specifies that the second line of the statement is postponed for milliseconds before execution (if this is executed using the plug-in the nodejs environment in Sublime, the interpreter may be different, ).
Note that the code to be postponed must be put into setTimeout in the form of a string because the engine uses the eval function to convert the string into code. If you postpone the execution of a function, you can directly put the function name into setTimeout. On the one hand, eval functions have security concerns. On the other hand, to facilitate JavaScript engine optimization code, the setTimeout method is generally in the form of a function name, as shown below.
Function func (){
Console. log (2 );
}
SetTimeout (func, 1000 );
// Or
SetTimeout (function () {console. log (2)}, 1000 );
SetTimeout parameters
In addition to the first two parameters, setTimeout allows you to add more parameters. They will be passed into the function (callback function) for deferred execution ).
SetTimeout (function (a, B ){
Console. log (a + B );
}, 1000,1, 1 );
In the above code, there are four parameters in setTimeout. The last two parameters will be used as callback function parameters when the callback function is executed after 1000 milliseconds.
In IE 9.0 and earlier versions, only setTimeout has two parameters and does not support more parameters. In anonymous functions, you can run the callback function with parameters, and then input the anonymous function with setTimeout; for example:
SetTimeout (function (){
MyFunc ("one", "two", "three ");
},1000 );
Of course, you can also use the bind or apply method to solve the problem.
For example, the bind method is used to bind redundant parameters to the callback function and generate a new function input setTimeout.
SetTimeout (function (arg1) {}. bind (undefined, 10), 1000 );
In the code above, the first parameter of the bind method is undefined, indicating that this of the original function is bound to the global scope, and the second parameter is the parameter of the original function to be passed in. It returns a new function without parameters.
SetTimeout notes
This in the callback function of setTimeout ()
If the callback function deferred by setTimeout is a method of an object, the this keyword in this method will point to the global environment, rather than the object in the definition.
Var x = 1;
Var o = {
X: 2,
Y: function (){
Console. log (this. x );
}
};
SetTimeout (o. y, 1000); // 1
The above code outputs 1 rather than 2, which indicates that this of o. y is not directed to o, but to the global environment.
Let's look at an example that cannot easily find errors.
Function User (login ){
This. login = login;
This. sayHi = function (){
Console. log (this. login );
}
}
Var user = new User ('John ');
SetTimeout (user. sayHi, 1000 );
The above code only shows undefined, because when user. sayHi is executed, it is executed in the global object, so this. login cannot get the value.
To prevent this problem, one solution is to put user. sayHi in an anonymous function for execution.
SetTimeout (function (){
User. sayHi ();
},1000 );
In the code above, sayHi is executed in the user scope, rather than in the global scope, so it can display the correct value.
Another solution is to bind sayHi to the user using the bind method.
SetTimeout (user. sayHi. bind (user), 1000 );
According to the html 5 standard, the shortest interval of setTimeout is 4 ms. To save power, the browser will extend the time interval to 1000 milliseconds for pages not in the current window. In addition, if the laptop is battery, Chrome and IE 9 or later versions will switch the time interval to the system timer, which is about 15.6 milliseconds.
SetTimeout execution callback interval
If you find the following content in a piece of code:
Var startTime = new Date ();
SetTimeout (function (){
Console. log (new Date ()-startTime );
}, 100)
What is the last print? The correct answer is that it depends on the amount of time it takes for the JS to be synchronized later.
That is, MAX (synchronous execution time, 100). If so, you have to check the setTimeout running mechanism.
2. setTimeout running mechanism
The running mechanism of setTimeout and setInterval is to remove the specified code from this execution. When the next Event Loop is executed, check whether the specified time has been reached. If so, execute the corresponding code. If not, wait for the next Event Loop to re-judge. This means that the code specified by setTimeout will be executed only after all the code executed this time is complete.
During each Event Loop, the tasks to be executed in the "task queue" are completed at one time. Both setTimeout and setInterval add tasks to the end of the "task queue. Therefore, they will not start until all the synchronization tasks of the current script are executed, and then wait until all the tasks in the "task queue" of the Event Loop are executed. It is not certain how long the previous task needs to be executed, so there is no way to ensure that the tasks specified by setTimeout and setInterval will be executed at the specified time.
SetTimeout (someTask, 100 );
VeryLongTask ();
The setTimeout code above specifies that a task will be run after 100 milliseconds. However, if the subsequent task (the synchronization task of the current script) is very time-consuming and cannot be completed after 100 milliseconds, then the delayed running someTask will have to wait, wait until the previous veryLongTask is finished.
3, setTimeout (func, 0)
When using the backbone framework to write code, new users always manipulate the dom during render due to some requirement factors, but find that the dom element status is changed, the code is correct, but the interface is not changed. Using setTimeout (func, time) can solve this problem, even if time = 0; there is only one truth to explore:
SetTimeout (func, 0) meaning
Who will execute func1 and func2 in the next generation? Obviously, func2 is executed first;
SetTimeout (function (){
Func1 ();
}, 0)
Func2 ();
SetTimeout is used to delay code execution to the specified time. If the specified time is 0, that is, setTimeout (f, 0), will the code be executed immediately?
The answer is No. Because the setTimeout running mechanism has said that the task specified by setTimeout must be executed only after the synchronization task of the current script and the existing events in the "task queue" are all processed. That is to say, the real function of setTimeout is to add an event after the existing event in the "task queue", which requires that a code segment be executed at a specified time. The events added by setTimeout are executed in the next Event Loop.
SetTimeout (f, 0) sets the second parameter to 0 to enable f to be in an existing task (the synchronization task of the script and the existing event in the task queue) execute the command immediately after the end. That is to say, setTimeout (f, 0) is used to execute the specified task as early as possible.
SetTimeout (function (){
Console. log ("Hello! ");
}, 0 );
The meaning of the above code is to display "Hello!" as early as possible !".
The task specified by setTimeout (f, 0) must be executed at the earliest until the next Event Loop. See the following example.
SetTimeout (function (){
Console. log ("Timeout ");
}, 0 );
Function a (x ){
Console. log ("a () start running ");
B (x );
Console. log ("a () end running ");
}
Function B (y ){
Console. log ("B () start running ");
Console. log ("input value:" + y );
Console. log ("B () end running ");
}
Console. log ("current task start ");
A (42 );
Console. log ("current task ended ");
// Start the current task
// A () starts running
// B () starts running
// The input value is 42.
// B () stops running
// A () stops running
// The current task ends.
// Timeout
The code above indicates that setTimeout (f, 0) must be executed after all synchronization tasks of the current script are completed.
0 milliseconds actually fail. According to the HTML5 standard, the time for setTimeOut to be postponed is at least 4 milliseconds. If the value is smaller than this value, it is automatically increased to 4. This is to prevent the continuous execution of multiple setTimeout (f, 0) statements, resulting in performance problems.
On the other hand, the browser uses a 32-bit signed integer to store the delayed execution time. This means that the setTimeout operation can only be postponed for a maximum of 2147483647 milliseconds (24.8 days). If this time is exceeded, the callback function will be executed immediately after the end of the current task queue, this is equivalent to setTimeout (f, 0.
4. setTimeout (f, 0) application
Adjust the event sequence
SetTimeout (f, 0) has several important functions. One of its major applications is to adjust the sequence of events. For example, in web development, an event first occurs in the child element and then bubbles to the parent element, that is, the event callback function of the child element, which is triggered before the event callback function of the parent element. If the event callback function of the parent element first occurs, setTimeout (f, 0) is used ).
Var input = document. getElementsByTagName ('input [type = button] ') [0];
Input. onclick = function (){
SetTimeout (function B (){
Input. value + = 'input ';
}, 0)
};
Document. body. onclick = function C (){
Input. value + = 'body'
};
The code above triggers callback function A and function C after clicking the button. In function A, setTimeout delays function B to the next Loop execution, so that it triggers the callback function C of the parent element first.
A user-defined callback function is usually triggered before the default action of the browser. For example, if you enter text in the input box, the keypress event is triggered before the browser receives the text. Therefore, the following callback function cannot reach the goal.
Document. getElementById ('input-box'). onkeypress = function (event ){
This. value = this. value. toUpperCase ();
}
The code above converts the characters to uppercase immediately after the user enters the text. But in fact, it can only convert the previous character to uppercase, because the browser has not received the text at this time, so this. value cannot get the character that is newly entered. The above code can be used only when setTimeout is used for rewriting.
Document. getElementById ('My-OK '). onkeypress = function (){
Var self = this;
SetTimeout (function (){
Self. value = self. value. toUpperCase ();
}, 0 );
}
The code above puts the code in setTimeout, which can be triggered after the browser receives the text; originally, this explains why the backbone calls render, dom manipulation is invalid because dom elements were not obtained at the time (why is there no error? This involves another topic). Naturally, when the page rendering is complete, the desired results are not displayed.
Split time any
As we all know, javascript is a single thread, and is characterized by blocking. If a program takes a long time to process, it can easily hold the entire page. What should I do if I cannot handle any interaction?
Simplified complexity? Complex logic backend processing? Html5 multithreading ?......
The above are all OK practices, but setTimeout is also a good tool to deal with such problems. A key usage of setTimeout is sharding. If a program is too large, we can split it into several small blocks. Because setTimeout (f, 0) actually means that tasks are executed in the earliest available idle time period of the browser. Therefore, tasks with large computing volume and long time consumption are usually put into several small parts, put them in setTimeout (f, 0) to execute (slice is inserted into the queue), so that even if the complex program is not completed, our operation page can also get immediate response. In fact, the interaction is inserted into a complex program for execution.
Var div = document. getElementsByTagName ('div ') [0];
// Write method 1
For (var I = 0xA00000; I <0 xFFFFFF; I ++ ){
Div. style. backgroundColor = '#' + I. toString (16 );
}
// Statement 2
Var timer;
Var I = 0x100000;
Function func (){
Timer = setTimeout (func, 0 );
Div. style. backgroundColor = '#' + I. toString (16 );
If (I ++ = 0 xFFFFFF) clearInterval (timer );
}
Timer = setTimeout (func, 0 );
The above code can be written in two ways: to change the background color of a webpage element. Writing a statement will cause the browser to be "congested", but writing a statement 2 won't. This is the benefit of setTimeout (f, 0. That is, you can use setTimeout to implement a pseudo-multithreading concept.
Another example of using this technique is code highlighting. If the code block is large, it is divided into small blocks and written as setTimeout (highlightNext, 50) for processing.
5, clearTimeout ()
The setTimeout and setInterval functions return an integer that represents the counter number. When the integer is passed into the clearTimeout and clearInterval functions, the corresponding timer can be canceled.
Var id1 = setTimeout (f, 1000 );
Var id2 = setInterval (f, 1000 );
ClearTimeout (id1 );
ClearInterval (id2 );
The integer returned by setTimeout and setInterval is continuous (in a certain environment, such as the browser console or js execution environment), that is, the integer returned by the second setTimeout method, it will be 1 larger than the first integer. You can write a function to cancel all current settimeouts.
(Function (){
Var gid = setInterval (clearAllTimeouts, 0 );
Function clearAllTimeouts (){
Var id = setTimeout (function () {}, 0 );
While (id> 0 ){
If (id! = Gid ){
ClearTimeout (id );
}
Id --;
}
}
})();
After running the above code, it is actually invalid to set any setTimeout.
The following is an example of the actual clearTimeout application. Some websites transmit users' input in the text box to the server via Ajax in real time. jQuery is written as follows.
$ ('Textarea '). on ('keylow', ajaxAction );
One major drawback of writing is that if you press keys consecutively, the keydown event is triggered consecutively, resulting in a large amount of Ajax communication. This is unnecessary and may cause performance problems. The correct method should be to set a threshold value to indicate the minimum interval between two Ajax communications. If a new keydown event occurs within the specified time, Ajax communication is not triggered and the timing starts again. If no new keydown event occurs after the specified time, the data will be sent through Ajax communication.
This method is called the debounce (anti-jitter) method to return a new function. The new function runs the actual task only when the interval between two triggers is greater than the preset value. Assuming that the interval between two Ajax communications is no less than 2500 milliseconds, the above code can be rewritten as follows.
$ ('Textarea '). on ('keylow', debounce (ajaxAction, 2500 ))
You can use setTimeout and clearTimeout to implement the debounce method. This method is used to prevent a function from being intensively called in a short period of time. Specifically, the debounce method returns a new version of this function. After this new function is called, the task is executed only when no new call is made within the specified time. Otherwise, the timer is re-executed.
Function debounce (fn, delay ){
Var timer = null; // declare a timer
Return function (){
Var context = this;
Var args = arguments;
ClearTimeout (timer );
Timer = setTimeout (function (){
Fn. apply (context, args );
}, Delay );
};
}
// Usage example
Var todoChanges = debounce (batchLog, 1000 );
Object. observe (models. todo, todoChanges );
In reality, <span style = "color: # ed1941"> It is best not to set too many setTimeout and setInterval </span>, which consume CPU. The ideal practice is to put all the code to be postponed in a function, and then only use setTimeout or setInterval for this function.
6. How to use setTimeout
SetTimeout is more than that, but it is powerful. So the question is, do you need to use it in a large amount in the project? Depends on the individual and the project. If you are not familiar with it, you are not recommended to use it more. After all, in some scenarios, setTimeout exists as an hack (it disrupts the lifecycle of a module and is difficult to debug when a problem occurs, you know), for example: before an instance is initialized, we use this instance. The error solution is to add a setTimeout when using the instance to ensure that the instance has been initialized before use.
However, as long as you are familiar with it and use the scenario (including the module lifecycle), it is understandable to use it. For example, many methods in underscore are also written based on the setTimeout method. For example, the very powerful _. defer: delays calling a function until the current call stack is cleared. This is similar to using the setTimeout method with a delay of 0. It is useful for computing with high execution overhead and HTML rendering without blocking UI threads. If the arguments parameter is passed, when the function is executed, arguments is passed as the parameter.
For example, debounce, the anti-jitter method mentioned above, is implemented as follows in underscore (_. debounce (function, wait, [immediate:
_. Debounce = function (func, wait, immediate ){
Var timeout, args, context, timestamp, result;
Var later = function (){
Var last = _. now ()-timestamp;
If (last <wait & last> = 0 ){
Timeout = setTimeout (later, wait-last );
} Else {
Timeout = null;
If (! Immediate ){
Result = func. apply (context, args );
If (! Timeout) context = args = null;
}
}
};
Return function (){
Context = this;
Args = arguments;
Timestamp = _. now ();
Var callNow = immediate &&! Timeout;
If (! Timeout) timeout = setTimeout (later, wait );
If (callNow ){
Result = func. apply (context, args );
Context = args = null;
}
Return result;
};
};