js执行顺序以及事件循环

因为js是单线程语言,当遇到异步任务(如ajax操作等)时,不可能一直等待异步完成,再继续往下执行,在这期间浏览器是空闲状态,显而易见这会导致巨大的资源浪费。

执行栈

当执行某个函数、用户点击一次鼠标,Ajax完成,一个图片加载完成等事件发生时,只要指定过回调函数,这些事件发生时就会进入执行栈队列中,等待主线程读取,遵循先进先出原则。

主线程

要明确的一点是,主线程跟执行栈是不同概念,主线程规定现在执行执行栈中的哪个事件。

主线程循环:即主线程会不停的从执行栈中读取事件,会执行完所有栈中的同步代码。

当遇到一个异步事件后,并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不同的队列中,我们称之为任务队列(Task Queue)。

当主线程将执行栈中所有的代码执行完之后,主线程将会去查看任务队列是否有任务。如果有,那么主线程会依次执行那些任务队列中的回调函数。



全局范围内的js代码、new Promise、Promise.then、Promise.all().then()、process.nextTick的执行顺序

在这里面由于new Promise会立即执行,这里面的代码会按照顺序依次执行。相应的顺序为:有顺序的js代码 --> new Promise --> 有顺序的js代码(全局js和new Promise执行完毕之后) --> 所有的process.nextTick --> Promise().then() --> Promise.all().then()

console.log(1);// 顺序-1

Promise.all([new Promise(resolve => {
	console.log(2);// 顺序-2
	resolve(100);
})]).then(values => {
  console.log(values);// 顺序- 10
});

process.nextTick(() => {
  console.log(6);// 顺序- 6
});

new Promise((resolve) => {
  console.log(3);// 顺序-3
  resolve('3-1');
}).then(values => {
  console.log(values);// 顺序- 8
});

console.log(4);// 顺序- 4

new Promise((resolve) => {
  console.log(5);// 顺序- 5
  resolve('5-1');
}).then(values => {
  console.log(values);// 顺序- 9
})
process.nextTick(() => {
  console.log(7);// 顺序- 7
})

涉及到setTimeout,以及定时器里面有new Promise、Promise.then、Promise.all的情况

这种情况的执行顺序是在第一种情况都执行完毕之后才会执行。执行顺序为:
多个定时器时间相同:按照顺序执行setTimeout。定时器里的执行顺序为,顺序执行js代码 --> new Promise --> 有顺序的js代码(js和new Promise执行完毕之后) --> 所有的process.nextTick --> Promise().then() --> Promise.all().then()。这实际就是重复第一种情况中的执行顺序。

setTimeout(() => {
  console.log("setTimeout1");// 顺序-- 1
  new Promise((resolve) => {
    console.log('setTimeout1 --- Promise');// 顺序-- 2
    resolve('Promise-1');
  }).then((values) => {
    console.log(values);// 顺序-- 5
  });
}, 0)
setTimeout(() => {
  console.log("setTimeout2");// 顺序-- 3
  new Promise((resolve) => {
    console.log('setTimeout2 --- Promise');// 顺序-- 4
    resolve('Promise-2');
  }).then((values) => {
    console.log(values);// 顺序-- 6
  });
}, 0)

宏任务和微任务

对于消息队列中的任务,分为两类:

  • 宏任务(macrotask ):setTimeout、setInterval
  • 微任务(microtask):promise

宏任务中包含了微任务,一个宏任务执行完成,开始下一个宏任务。

    console.log("a")
    let r = new Promise(function (resolve, reject) {
      console.log("b");
      resolve()
    });
    r.then(() => console.log("c"));
    setTimeout(() => { console.log("d") }, 0)
    setTimeout(() => { console.log("e") }, 1000)
    console.log("f")

看这几行代码

  1. 开始执行,发现了一些代码,放进一个宏任务中
  2. 先执行a
  3. 执行b
  4. 发现异步操作then,属于微任务,把他添加进当前宏任务中的微任务的队列
  5. 发现定时器d,setTimeout属于宏任务,添加到宏任务的队列
  6. 发现定时器e,setTimeout属于宏任务,添加到宏任务的队列
  7. 执行f
  8. 代码都已经执行完成,开始执行微任务队列,打印出c
  9. 微任务队列执行完成,开始执行下一个宏任务队列
  10. 直接打印出d,没有其他微任务,开始执行下一个宏任务队列
  11. 打印出e,所有宏任务执行完成
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值