js代码执行顺序,浅谈Event Loop

js代码执行顺序

1、同步代码会按照顺序执行,发现异步代码会根据类型分别放入宏队列微队列

宏队列macrotask,也叫tasks,其中包含

  • setTimeout
  • setInterval
  • setImmediate (Node独有)
  • requestAnimationFrame (浏览器独有)
    I/O
  • UI rendering (浏览器独有)

微队列microtask,也叫jobs,其中包含

  • process.nextTick (Node独有)
  • Promise
  • Object.observe
  • MutationObserver

2、同步代码执行完之后调用栈Stack会清空。
3、然后按顺序取出微队列中的任务放入调用栈Stack中执行,直到把微队列中的任务执行完毕。若执行过程中又产生了微队列的任务,那么会排在本次执行的微队列后面在本次执行。
4、微队列执行完毕后,微队列microtask和调用栈Stack都为空队列。
5、接着取出宏队列中的首个任务放入调用栈Stark中执行。
6、重复执行1-5步骤。

举个列子:

console.log(1);

setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
});

new Promise((resolve, reject) => {
  console.log(4)
  resolve(5)
}).then((data) => {
  console.log(data);
})

setTimeout(() => {
  console.log(6);
})

console.log(7);

输出结果:

1
4
7
5
2
3
6

根据上面所讲的分析下此块代码:
1、首先毫无疑问的输出第一行同步代码 1。
2、按顺序执行遇见setTimeout,放入宏队列,此时

  • 宏队列任务:
let macrotask = 
[
setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
})
]
  • 微队列任务:
let microtask = []

3、继续往下执行遇见Promise,会同步执行Promise内的代码,.then()的回调会被放入微队列中,执行到这里输出1 4,此时:

  • 宏队列任务:
let macrotask = 
[
setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
})
]
  • 微队列任务:
let microtask = 
[
(5) => {
  console.log(5);
}
]

4、继续往下执行又遇见定时器,放入宏队列,无新输出,输出还为1 4,此时:

  • 宏队列任务:
let macrotask = 
[
setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
}),
setTimeout(() => {
  console.log(6);
})
]
  • 微队列任务:
let microtask = 
[
(5) => {
  console.log(5);
}
]

5、继续执行console.log(7),输出1 4 7,宏队列、微队列为变化。
6、同步任务执行完毕,开始按顺序执行微队列任务输出5,这个周期微队列清空,现在输出1 4 7 5,此时:

  • 宏队列任务:
let macrotask = 
[
setTimeout(() => {
  console.log(2);
  Promise.resolve().then(() => {
    console.log(3)
  });
}),
setTimeout(() => {
  console.log(6);
})
]
  • 微队列任务:
let microtask = []

7、同步任务以及微队列任务执行完毕,开始执行宏队列首个任务重复以上操作,先执行console.log(2)打印出2,接着遇见Promise加入微队列,目前输出1 4 7 5 2,此时:

  • 宏队列任务:
let macrotask = 
[
setTimeout(() => {
  console.log(6);
})
]
  • 微队列任务:
let microtask = 
[
 () => {
    console.log(3)
  }
]

8、该周期同步任务执行完毕,执行微队列任务打印3,现在输出1 4 7 5 2 3,此时微队列实行完毕,继续执行宏队列首任务,此时

  • 宏队列任务:
let macrotask = 
[
setTimeout(() => {
  console.log(6);
})
]
  • 微队列任务:
let microtask = []

9、执行微队列首个任务console.log(6),打印出6,此时输出1 4 7 5 2 3 6,此时宏队列、微队列和执行栈都执行完毕清空,本次代码执行完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JS的事件循环是指JS引擎在执行任务时的一种机制。在浏览器中,事件循环是由浏览器来实现的,而在NodeJS中也有自己的事件循环实现。事件循环的基本原理是将待处理的任务按顺序存放在一个任务队列中,然后从队列中取出任务并执行。在事件循环中,任务可以分为宏任务和微任务两种类型。宏任务包括整体的script代码、setTimeout、setInterval等,而微任务则包括Promise、MutationObserver等。在事件循环的执行过程中,微任务的执行优先于宏任务。 具体来说,事件循环的流程如下: 1. 执行当前的同步任务,即执行JS代码中的同步代码。 2. 检查是否存在微任务,如果存在,则按照先进先出的顺序依次执行微任务,直到微任务队列为空。 3. 当前的宏任务执行完成后,检查是否存在新的宏任务。如果存在,则执行下一个宏任务,否则继续等待新的任务加入队列。 4. 重复步骤2和步骤3,直到任务队列为空。 在NodeJS中,除了浏览器中的事件循环机制外,还有一些差异和新增的任务类型和任务阶段。具体来说,NodeJS的事件循环包括以下几个阶段: 1. timers阶段:执行定时器回调函数。 2. pending callbacks阶段:执行延迟到下一个循环迭代的I/O回调函数。 3. idle, prepare阶段:仅在内部使用。 4. poll阶段:检索新的I/O事件;执行I/O相关的回调函数。 5. check阶段:执行setImmediate()的回调函数。 6. close callbacks阶段:执行关闭的回调函数,如socket.on('close', ...)。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值