从setTimeout简单了解js事件模型

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

内容简介:先从一个例子入手:输出结果很容易知道:在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的事件模型


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

查看所有标签

猜你喜欢:

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

高性能JavaScript

高性能JavaScript

Nicholas C.Zakas / 丁琛、赵泽欣 / 电子工业出版社 / 2010-11 / 49.00元

如果你使用JavaScript构建交互丰富的Web应用,那么JavaScript代码可能是造成你的Web应用速度变慢的主要原因。《高性能JavaScript》揭示的技术和策略能帮助你在开发过程中消除性能瓶颈。你将会了解如何提升各方面的性能,包括代码的加载、运行、DOM交互、页面生存周期等。雅虎的前端工程师Nicholas C. Zakas和其他五位JavaScript专家介绍了页面代码加载的最佳方......一起来看看 《高性能JavaScript》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器