4

【JavaScript基础】Js的定时器(你想看的原理也在哟)

 2 years ago
source link: https://segmentfault.com/a/1190000040895853
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【JavaScript基础】Js的定时器(你想看的原理也在哟)

博客说明

文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢!

本章是经历第二次翻新,时过一年,再看自己的文章,觉得需要做点什么,它得丰富一点!篇幅半页或者一页,自己都感觉有点对不住自己。为了对得住自己,加了原理解析和案例。知其然与所以然。

Js的定时器,是前端的基本工具,在日常的开发和工作上也会经常的使用到。前端的定时器有两种,一种是一次性定时器,一种是重复性定时器。

一次性定时器setTimeout

标准:在指定的毫秒数后调用函数或计算表达式。

口语:使一段代码在指定时间后运行。

setTimeout(code,millisec,lang)
参数描述code必需。要调用的函数后要执行的 JavaScript 代码串。millisec必需。在执行代码前需等待的毫秒数。lang可选。脚本语言可以是:JScript \ VBScript \ JavaScript
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Js的定时器</title>
</head>

<body>

    <p>点击按钮,在等待 3 秒后弹出 "Hello"。</p>
    <button onclick="myFunction()">我是按钮,点我</button>

    <script>
        function myFunction() {
            setTimeout(function () {
                alert("Hello")
            }, 1000 * 3);
        }
    </script>

</body>

</html>

重复性定时器setInterval

标准:按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。

口语:可以使一段代码每过指定时间就运行一次。

setInterval(code,millisec,lang)
参数描述code必需。要调用的函数或要执行的代码串。millisec必须。周期性执行或调用 code 之间的时间间隔,以毫秒计。lang可选。 JScript \ VBScript \ JavaScript
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Js的定时器</title>
</head>

<body>

    <input id="clock" />

    <button onclick="clearDate()">别变了,快停止吧,点我!</button>

    <script type="text/javascript">
        const id = setInterval(() => {
            const date = new Date();
            const time = date.toLocaleTimeString();
            document.getElementById("clock").value = time;
        }, 1000);

        function clearDate() {
            clearInterval(id)
        }
    </script>

</body>
  
</html>
时间的误差

setInterval指定的是<span style="color: red">开始执行</span>之间的间隔,并不考虑每次任务执行本身所消耗的时间。因此实际上,两次执行之间的间隔会小于指定的时间。

比如,setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。

为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。

var i = 1;
var timer = setTimeout(function() {
  alert(i++);
  timer = setTimeout(arguments.callee, 2000);
}, 2000);

消除定时器

在使用定时器的时候,需要有一个好的习惯,那就是清除定时器,特别是对于重复型定时器,一定要及时清除。

定时器清除的方法

相对于两种创建定时器的方法,Js也给出了相对应的清除方法,分别是clearTimeout(obj)clearInterval(obj)

在看到这两种方法都是接收一个参数,这个参数就是定时器的标识,这个标识在使用定时器的时候被定义用来接收定时器方法的变量。

// 一秒之后打印
const test1 = setTimeout(function(){
   console.log('hello world')
},1000);

// 每秒打印一次
const test2 = setInterval(function(){
    console.log('hello world')
},1000)

// 清理定时器
clearTimeout(test1);
clearInterval(test2)
JavaScript语言特性

JavaScript是一门基于对象的弱类型语言,它作为浏览器脚本语言,主要用途是负责与页面的交互,以及操作DOM。

重点来了,JavaScript的执行环境是单线程的,即默认情况下是同步加载的,也就是说 JavaScript的加载是阻塞的。在同一时间内JavaScript只能完成一件事,自上而下执行,下面的代码等待上面的代码解析完成。

在这种情况下,后面的代码其实就是被阻塞了。阻塞就意味着等待,等待就意味着用户体验,用户体验一来,那必须得使劲想办法,所以同步和异步出现了。

同步和异步

同步操作:队列执行。

异步操作:并线执行。

异步的任务不具有阻塞效应。

同步任务都是在主线程中执行,形成了一个执行栈,直到主线程空闲时,才会去事件队列中查看是否有可执行的异步任务,如果有就推入主进程中。

异步任务在JavaScript中是通过回调函数实现异步的,回到本文的主题,一旦使用了setTimeout(),里面的回调函数就是异步代码,但是这里面的代码不会立马执行,而是要等待主队列为空,并达到定的延时时间才会执行。

setTimeoutsetInterval的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。

这意味着,setTimeoutsetInterval指定的代码,必须等到本轮Event Loop的所有同步任务都执行完,再等到本轮Event Loop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证在时间内执行。

setTimeout(function() {
  console.log("异步任务执行");
}, 0);
 
function a(x) {
  console.log("a() 开始运行");
  b(x);
  console.log("a() 结束运行");
}
 
function b(y) {
  console.log("b() 开始运行");
  console.log(y);
  console.log("b() 结束运行");
}
 
console.log("同步任务开始");
a("hello world");
console.log("同步任务结束");
 
// 同步任务开始
// a() 开始运行
// b() 开始运行
// hello world
// b() 结束运行
// a() 结束运行
// 同步任务结束
// 异步任务执行
  • JavaScript引擎是单线程,它会强制异步事件排队等待执行;
  • setTimeout和setInterval执行原理是不一样的,需要注意他们的执行时间的影响;
  • 如果一个一次性定时器(setTimeout)被阻塞了,它会等待直到有合适的执行时间(等待时间有可能比它定义的延迟时间长);
  • 如果重复性定时器(setInterval)回调函数执行时间很长(长于定义的间隔时间)的话,间隔定时器有可能无间隔的持续执行。

感谢

万能的网络

菜鸟教程

以及勤劳的自己,个人博客GitHub测试GitHub

公众号-归子莫,小程序-小归博客


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK