In the actual development process, we often encounter requirements such as entering the page for the first time to give corresponding prompts, and then disappearing automatically after a specified time or displaying the front-end clock.
According to the traditional scheme, we can use setTimeout
the implementation . But it exists: the actual delay is longer than the set value.
setTimeout is not on time
There are many factors that can cause setTimeout callbacks to take longer than expected.
Minimum delay >= 4ms
- If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4. – HTML5 spec Timers
In the browser, because the function is nested to a certain depth, it will be blocked.
function cb() {
setTimeout(cb, 0)
}
setTimeout(cb, 0)
Timing minimum delay for inactive tabs >=1000ms
In order to optimize the tab loading loss (and reduce power consumption), the minimum delay of the timer in the inactive tab is limited to 1S (1000ms).
timeout delay
In addition to the "minimum delay", the timer may still be delayed because the current page (or the operating system/browser itself) is occupied by other tasks.
It should be emphasized that callback functions and code sections cannot be executed until the setTimeout()
calling main thread has finished performing other tasks.
Maximum delay value
Browsers including IE, Chrome, Safari, and Firefox store delays internally as 32-bit signed integers. This will cause an overflow if a delay is greater than 2147483647 milliseconds (about 24.8 days), causing the timer to be executed immediately. -- The setTimeout/setInterval delay value is too large
Breaking the 4ms limit
If you want to implement a 0ms delay timer in the browser, you can try the following method
(function() {
var timeouts = [];
var messageName = "zero-timeout-message";
function setZeroTimeout(fn) {
timeouts.push(fn);
window.postMessage(messageName, "*");
}
function handleMessage(event) {
if (event.source == window && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
window.addEventListener("message", handleMessage, true);
window.setZeroTimeout = setZeroTimeout;
})();
CSS is more punctual
If you want to implement a particularly punctual business scenario (such as a clock ). Obviously setTimeout/setInterval is not the best practice. How to avoid synchronous blocking is an important point to break through this problem.
Here, using CSS animation to achieve, CSS animation has several significant advantages:
- Does not rely on javascript, and has mature related APIs;
- Works well, even on low performance systems. The rendering engine will use frame skipping or other techniques to ensure that the animation performance is as smooth as possible;
- Lets the browser control the animation sequence, allowing the browser to optimize performance and effects, such as reducing the frequency of animation updates located in hidden tabs.
The animation attribute is a shorthand attribute form of the animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, and animation-play-state attributes.
Attributes | illustrate | example |
---|---|---|
animation-name |
Specifies a sequence of animations to apply | animation1,animation2 |
animation-duration |
Specify the duration of an animation cycle in s or ms | 60s |
animation-timing-function |
The cadence to execute in each animation cycle | ease 、linear 、steps(60) |
animation-delay |
Define when the animation starts, in s or ms | 100ms |
animation-iteration-count |
Defines the number of times the animation will run before ending | infinite (unlimited times),3 |
animation-direction |
Indicates whether the animation plays in reverse | normal 、alternate 、reverse |
animation-fill-mode |
Sets how CSS animations apply styles to their targets before and after execution | forwards 、backwards |
animation-play-state |
Defines whether an animation is running or paused | running 、paused |
animation: timer 60s infinite steps(60) forwards;
steps(number_of_steps, direction)
: Defines a step function that divides the domain of output values equidistantly.
Bind the value to be displayed via a custom data property. In this way, in css, expressions can be used attr()
to obtain values.
<div class="container">
<p data-seconds="00 01 02 03 04 05 06 07 08 09"></p>
</div>
The current value is displayed through a pseudo-element (only one is displayed at a time), and then the duration of the animation cycle is 10s, and the equidistant division is divided into 10 steps.
The ordinate of the moving vector every 1s.
.container p {
height: 68px;
width: 68px;
line-height: 68px;
overflow: hidden;
}
.container p::after {
display: block;
content: attr(data-seconds);
animation: timer 10s infinite steps(10) forwards;
}
@keyframes timer {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, -100%, 0);
}
}