同步异步,宏任务和微任务,事件循环

110 阅读2分钟

js单线程

console.log('script start');

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

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');
//控制台输出
script start
script end
promise1
promise2
setTimeout

js执行流程

js执行流程 (@知乎Miku)

  1. 同步和异步任务分入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
  2. 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
  3. 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
  4. 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
  • 主线程内的任务执行为空的判定: 在js引擎中,存在一个叫monitoring process的进程,这个进程会不断的检查主线程的执 行情况,一旦为空,就会去Event Quene检查有哪些待执行的函数。

宏任务和微任务

  • 宏任务: setTimeout setInterval js主代码 setImmediate(Node) requestAnimationFrame(浏览器)
  • 微任务: process.nextTick Promise的then方法

宏任务和微任务的执行:

**他们都从属于异步任务,主要区别在于他们的执行顺序,Event Loop的走向和取值**

宏任务和微任务的执行

  1. 存在微任务的话,就执行所有的微任务
  2. 微任务都执行完之后,执行下一个宏任务
  3. 1,2以此循环
  • process.nextTick(callback)类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数
  • 如果想异步任务尽可能快地执行,那就使用process.nextTick
  • 根据语言规格,Promise对象的回调函数,会进入异步任务里面的“微任务”(microtask)队列
  • 微任务队列追加在process.nextTick队列的后面。也属于本轮循环。所以,下面的代码总是先输出3,再输出4
process.nextTick(()=>console.log(3))
promise.resolve().then(()=>console.log(4))
//控制台输出:
//3
//4
  • 需要注意,只有前一个队列完全清空后,才会执行下一个队列
process.nextTick(()=>console.log(1))
promise.resolve().then(()=>console.log(2))
process.nextTick(()=>console.log(3))
promise.resolve().then(()=>console.log(4))
//输出为
//1
//3
//2
//4
//上面的代码中,process.nextTick的回调会早执行于Promise
  • 下面代码的输出顺序为:
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