【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指定的是开始执行之间的间隔,并不考虑每次任务执行本身所消耗的时间。因此实际上,两次执行之间的间隔会小于指定的时间。

比如,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

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

【JavaScript基础】Js的定时器(你想看的原理也在哟)的更多相关文章

  1. Javascript 基础--JS函数(三)

    一.基本概念:未完成某一个功能的代码(语句,指令)的集合. 二.函数的调用方式: 2.1.函数名(传递参数1,传递参数2)   基本语法 function 函数名(参数列表){ //代码; retur ...

  2. Javascript基础 - js中曾经忽略的知识点

    深入那些曾经忽略的Javascript知识 1. parseInt(string, [radix]),parseFloat(string) 一般我们省略第二个参数,parseInt(‘100’) == ...

  3. javascript基础-js对象

    一.js对象的创建 1.普通最简单的方式 var teacher = new Object( ); teacher.name = "zhangsan"; teacher.age = ...

  4. javascript基础-js继承

    1.prototype方式 示例:没有使用prototype(下列这些代码只能获取array1数组的总和,而无法对array2数据进行求和) var array1 = new Array(1,4,9, ...

  5. JavaScript基础 -- js常用内置方法和对象

    JS中常用的内置函数如下: 1.eval(str):计算表达式的结果. 2.parseInt(str,n):将符串转换成整数数字形式(可指定几进制). 3.parseFloat(str):将字符串转换 ...

  6. javascript基础-js函数

    一.创建函数的方式 1)普通方式 function cal( num1, num2 ) { return num1+num2; } 2)使用变量初始化方式 var plus = function(nu ...

  7. JavaScript(JS)简介

    历史背景介绍 (Brendan Eich)在其Netscape Navigator 2.0产品中开发出一套livescript的脚本语言.Sun和Netscape共同完成.后改名叫Javascript ...

  8. JavaScript——基础知识,开始我们的js编程之旅吧!

    JavaScript基础第01天 1. 编程语言 编程语言: 可以通过类似于人类语言的"语言"来控制计算机,让计算机为我们做事情,这样的语言就叫做编程语言(Programming ...

  9. 【JavaScript】JS的坚实基础

    前言 ​ 考虑到在后面的开发中,需要大量的使用js语言去进行开发,所以准备重新规整一下javascript的知识点,专门开了一个js的专栏,用来复习一下js语言.万事开头难,要是后面写的有问题的,欢迎 ...

随机推荐

  1. input竖直的输入框,文字从上到下排列

    有的时候可能会有这样的需求,一个竖直的输入框,输入信息,文字也是从上到下排列: (但是在移动端或用轮播swiper时不起作用,可以用textarea代替input) <!DOCTYPE html ...

  2. git报错:Auto Merge Failed; Fix Conflicts and Then Commit

    本文来源:http://blog.csdn.net/trochiluses/article/details/101007191.出错场景: 协同开发时,我们从远程服务器上pull下代码的时候,出现以下 ...

  3. 解决IE浏览器 点击子元素重复调用执行 mouseover 与mouseout兼容性问题

    将函数配对换为下面2个就可以解决兼容性问题. mouseenter() mouseleave(0

  4. dedecms描述文字description长度截取办法

    [field:description  function='cn_substr(@me,126)' /]

  5. Shell系列(23)- 字符截取命令sed

    简述 字符替换命令sed 和vi功能相似,但是vi是给用户用的,sed是给脚本用的 sed是一种几乎包括在所有的UNIX平台(包括Linux)的轻量级流编辑器.s sed主要是用来将数据进行选取.替换 ...

  6. 华为云计算IE面试笔记-FusionCompute虚拟机热迁移定义,应用场景,迁移要求,迁移过程

    *热迁移传送了什么数据?保存在哪? 虚拟机的内存.虚拟机描述信息(配置和设备信息).虚拟机的状态 虚拟机的配置和设备信息:操作系统(类别.版本号).引导方式(VM通过硬盘.光盘.U盘.网络启动)和引导 ...

  7. P4606-[SDOI2018]战略游戏【圆方树,虚树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4606 题目大意 给出\(n\)个点\(m\)条边的一张图,\(q\)次询问给出一个点集,询问有多少个点割掉后可以 ...

  8. 微信小程序Canvas添加水印字体,通过setGlobalAlpha设置字体透明度。

    微信小程序自带的设置透明度只有setGlobalAlpha,但是CanvasContext.setGlobalAlpha设置透明度,是全局透明,整张图片都透明了.所以直接使用是不行的. 换种思路实现: ...

  9. mysql8 主从搭建

    主:192.168.10.2 从:192.168.10.3 主:1.登录mysql,授权账号,让从数据库可以进行复制. mysql CREATE USER 'repl'@'192.168.10.3' ...

  10. Xcode相关

    Xcode相关的路径 Provisioning Profiles存放路径:~/Library/MobileDevice/Provisioning Profiles 所有模拟器(包括历史模拟器):~/L ...