pg1991
pg1991
6月前 · 4 人阅读 · 文章来源: 简书

1. 任务分类

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise,process.nextTick

2. 时间循环的顺序,决定了JS代码的执行顺序(参考文章)

进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务

setTimeout(function() {
    console.log('setTimeout');
})

new Promise(function(resolve) {
    console.log('promise');
    resolve()
}).then(function() {
    console.log('then');
})

console.log('console');
//promise
//console
//then
//setTimeout
  • 这段代码作为宏任务,进入主线程。
  • 先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
  • 接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue。
  • 遇到console.log(),立即执行。
  • 好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
  • ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event - Queue中setTimeout对应的回调函数,立即执行。
  • 结束。
console.log('1');
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
//参考文章中的结果:1,7,6,8,2,4,3,5,9,11,10,12
//node执行环境结果:1,7,6,8,2,4,9,11,3,10,5,12

3. 个人理解

  • chrome中整体代码结束后,执行微任务queue中的所有任务,第一次eventLoop结束;
    执行宏任务queue中的第一个任务,再执行微任务queue中的所有任务,第二轮eventLoop结束;
    执行宏任务queue中的第二个任务,再执行微任务queue中的所有任务,第二轮eventLoop结束;
    ...
//实测数据
console.log('1');
setTimeout(function() {
    console.log('2');
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
    setTimeout(()=>{
        console.log('haha')
    })
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
//node中的结果:1,7,8,2,4,9,11,5,12,haha
//chrome浏览器中的结果:1,7,8,2,4,5,9,11,12,haha

总结

  • chrome中的宏queue中的第一个任务执行一下,并执行完微queue中的所有任务,就跳到宏queue第二个任务(此时宏queue最后一个是之前宏queue中的第一个任务里面的setTimeout),执行完就开始执行完微queue中的所有任务
  • node的事件循环机制,对一些容易堵塞的操作,数据库 文件系统等I/O操作,包括HTTP请求等等会委托给底层的线程池执行,并会告诉线程池一个回调函数,这样单线程继续执行其他事情,当这些堵塞操作完成后,其结果与提供的回调函数一起再放入队列中。在下次清空微queue中就会执行到(顺序不一定正确且唯一)
  • node和chrome在事件循环的规律上是一致的,只是node会把一些微任务直接交由子线程处理,处理结束后才会出现在微队列中
  • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
  • 当指定的事情完成时,Event Table会将这个函数移入Event Queue。==(Promise resolve之后then函数才会进入Event Queue)==
  • 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
收藏 0
关键词: console log function 任务 resolv
评论