从setTimeout简单了解js事件模型

先从一个例子入手:

(function() {
  console.log('开始执行')

  setTimeout(function fun1() {
    console.log('第一个延时函数消息')
  })

  console.log('一条消息')
  
  setTimeout(function fun2() {
    console.log('第二个延时函数消息')
  }, 0)

  console.log('结束')

})();

输出结果很容易知道:

//开始执行
//一条消息
//结束
//第一个延时函数消息
//第二个延时函数消息

在js事件模型中,运行时从最先进入队列的消息开始处理队列中的消息,这不难理解,但上述代码为什么setTimeout延时为0也会延后执行?

这是因为在js中,

  • 所有的同步任务在主线程上按顺序执行,前一个任务执行完毕,才能执行后一个任务
  • 主线程之外有一个任务队列,像setTimeout,promise.then,await promise这种的异步任务在任务队列上先按等级再按顺序排队,等级是什么鬼?异步任务也是分等级的,promise.then排第一梯队,await promise排第二梯队,,最后就是setTimeout,按等级排好队后再按顺序排好队(见下面示例)
  • 当主线程中的同步任务执行完毕后,就会通知任务队列中的任务:主线程上的同步任务执行好了,你们可以来主线程了。然后排好队进入主线程,开始执行异步任务
  • 总的来讲就是只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
setTimeout(()=>{
  console.log("11")
})

setTimeout(()=>{
  console.log("12")
},0)

function promise_func(){
  return new Promise((resolve,reject)=>{
      resolve("异步输出结果")
  })
}

promise_func().then(data=>{
  console.log('then', data)
})

async function fun1(){
  console.log('await1', await promise_func())
}
fun1()

async function fun2(){
  console.log('await2', await promise_func())
}
fun2()

promise_func().then(data=>{
  console.log('then2', data)
})

console.log("22")

打印结果:

22
then 异步输出结果
then2 异步输出结果
await1 异步输出结果
await2 异步输出结果
11
12

事件模型中加入消息队列神马的一般来说你不去关心是看不清摸不着的,但根据setTimeout你可以稍微简单的感受到里面的一些情况

不多说,先放一个简单例子:

(function() {
  console.log('开始');

  setTimeout(function cb() {
    console.log('第一个延时器的消息');
  },1001);

  console.log('一条消息');

  setTimeout(function cb1() {
    console.log('第二个延时器的消息');
  }, 1000);

  console.log('结束');
})()

可能你会有点犹豫了,其实结果是:

开始
一条消息
结束
第一个延时器的消息
第二个延时器的消息

为啥第一个延时1.001s比第二个延时1.000s要先执行呢,我们先从setTimeout说起

setTimeout没跟同步函数一起被加入到消息队列,而是等待同步消息队列执行结束开始加入,延迟参数代表消息被实际加入到队列的最小延迟时间

如果队列中没有其它消息,在这段延迟时间过去之后,消息会被马上处理。但是,如果有其它消息,setTimeout 消息必须等待其它消息处理完。

上述代码中,第一个延时函数被加入到消息队列,并立即开始执行,等待1.001s后输出结果,在第一个延时函数加入到队列并立即执行这一过程中,第二个延时函数也加入了队列,这个加入到队列的过程是需要一定时间的,这个时间取决于cpu的处理速度,当然这个时间是非常短的。

上面是一个简单例子,我们夸大一下这个例子,试着让最后一个延时1秒的函数等待更多的时间再去执行,比第一个延时1.0002s的延时函数还要慢,方案就是在这过程中让更多的延时函数加入消息队列。

(function () {

  console.log('开始')

  setTimeout(function cb() {
    console.log('第一个延时器的消息')
  }, 1002)

  console.log('一条消息')

  for (let i of new Array(1000)) {
    setTimeout(function cb1() {
      console.log('nb')
    }, 2000)
  }

  setTimeout(function cb1() {
    console.log('最后一个延时器的消息')
  }, 1000)

  console.log('结束')
})()

执行结果:

开始
一条消息
结束
第一个延时器的消息
最后一个延时器的消息
nb
nb
...
...

第一个延时函数被加入到消息队列,并立即开始执行,等待1.002s后输出结果,当在最后一个延时函数加入队列前循环加入1000个延时函数时,
最后一个延时函数是等待前面所有延时函数加入队列后才开始加入并执行,这个加入队列的过程花费了一段时间,导致1.002s后第一个延时函数执行结果最先被输出

这些示例虽然简单,但能很好地帮助理解setTimeout延时的含义以及js的事件模型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值