从setTimeout简单了解js事件模型

栏目: 后端 · 发布时间: 5年前

内容简介:先从一个例子入手:输出结果很容易知道:在js事件模型中,运行时从最先进入队列的消息开始处理队列中的消息,这不难理解,但上述代码为什么setTimeout延时为0也会延后执行?

先从一个例子入手:

(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的事件模型


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Redis实战

Redis实战

Josiah L. Carlson / 黄健宏 / 人民邮电出版社 / 2015-10

【内容简介】 本书深入浅出地介绍了Redis的5种数据类型,并通过多个实用示例展示了Redis的用法。除此之外,书中还讲述了Redis的优化方法以及扩展方法,是一本对于学习和使用 Redis 来说不可多得的参考书籍。 本书一共由三个部分组成。第一部分对Redis进行了介 绍,说明了Redis的基本使用方法、它拥有的5种数据结构以及操作这5种数据结构的命令,并讲解了如何使用Redis去构......一起来看看 《Redis实战》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具