JavaScript之执行机制

导读

之前对js的执行机制一知半解,导致使用setTimeoutsetInterval函数时老是犯一些比较低级的错误。这篇文章就来系统地总结一下,先来看代码

const s = new Date();
const fn = () => {
    let i = 0;
    while (i < 2000000000) {
        i++;
    }
    console.log(Math.floor(new Date() - s) / 1000, "秒");
}
setInterval(fn, 1000);

思考:上面这些到底会打印啥?

答案:

2.733 “秒”
4.375 “秒”
6.047 “秒”
7.698 “秒”
9.402 “秒”
11.068 “秒”

再看看这个函数的执行时间,大约是1.65s

const fn = () => {
    let i = 0;
    while (i < 2000000000) {
        i++;
    }
}
console.time("时间");
fn();
console.timeEnd("时间")    

时间: 1656.19091796875 ms

我们发现,只有第一个打印的是 a 1 = 1.65 + 1 a_1 = 1.65 + 1 a1=1.65+1
其他的全是 a n = a n − 1 + 1.65 a_n = a_{n-1} + 1.65 an=an1+1.65,这与我们设置的1s后再执行fn的的情况不符合
理应是 a n = a n − 1 + 1.65 + 1 a_n = a_{n-1} + 1.65 + 1 an=an1+1.65+1,这是为什么呢?

js的任务类型说起

同步

同步任务很简单,即单线程的执行方式,一条路走到黑。js是基于同步的语言

异步

js的异步任务有很多种,下面简单地分类一下

  1. 资源请求(如图片加载、请求数据
  2. 定时器任务,如setTimeout,setInterval
  3. 事件。如onclick, onmousedown

既然js是基于同步的语言,那js是如何实现异步的呢?

js的执行

js会把执行的内容放到以下的两个地方

  1. 执行栈
  2. 任务队列(消息队列

就像这样
在这里插入图片描述

事件执行的逻辑为
在这里插入图片描述
所以执行顺序为

  1. 先执行执行栈中的任务,如果是异步任务,则交给异步处理函数处理
  2. 执行栈为空时,则把任务队列中的任务取出。
  3. 重复1-2的过程,直到执行栈和任务队列都为空时,程序结束

结合开始的代码描述上述过程

const s = new Date();
const fn = () => {
    let i = 0;
    while (i < 2000000000) {
        i++;
    }
    console.log(Math.floor(new Date() - s) / 1000, "秒");
}
setInterval(fn, 1000);

setInterval的真正含义是,每隔1000ms,就把一个fn函数放进消息队列

过程:

  1. 主栈中按顺序依次执行,遇到fn函数时,第1000ms把fn放入任务队列
  2. 把fn取出,执行fn(大约需要执行1.65s,约2.7s fn执行结束打印2.7s,但是在第2000ms时,又把另外一个fn加入了任务队列。但到第2.7s才开始执行,执行完成后打印4.3s
  3. 依次类推,所以开始是第2.7s是第一个程序执行完成后的打印事件,后面每隔1.65s打印一次

就像这样,其中橙色的线为在队列中的等待时刻,蓝色的线是执行时刻

在这里插入图片描述
可以看到,每个fn之间是连续执行的

如果想要每个fn之间相隔了1s才执行,可以这样写

let myInterval = function(fn, delay) {
  function inside() {
    fn();
    setTimeout(inside, delay);
  }
  setTimeout(inside, delay);
}
myInterval(dosomthing(), 1000);

参考

  1. JavaScript用setTimeout模拟实现setInterval - Web前端工程师面试题讲解
  2. 这一次,彻底弄懂 JavaScript 执行机制
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值