Event Loop

事件循环是一个可以写好几篇文章的话题,在面试中大多是考察对异步的执行结果,本意是考察对事件循环的理解。

现象:

  • macro-task(宏任务): setTimeoutsetIntervalsetImmediateI/O
  • micro-task(微任务):process.nextTick, 原生Promise(有些实现的promise将then方法放到了宏任务中),MutationObserver
  • 先入先出的顺序再按宏任务和微任务进行执行
  • promise(立即执行) > nextTick > then > setTimeout > setImmediate

例题1

async function test () {
    console.log(1)
}

async function run () {
    await test();
    console.log(2)
}

run ()

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

new Promise((resolve, reject) => {
    resolve();
    console.log(5)
}).then(res => {
    console.log(res, 6)
}).then((a) => {
    console.log(7)
})


console.log('glob1');

setTimeout(function() {
    console.log('timeout1');
    process.nextTick(function() {
        console.log('timeout1_nextTick');
    })
    new Promise(function(resolve) {
        console.log('timeout1_promise');
        resolve();
    }).then(function() {
        console.log('timeout1_then')
    })
})

setImmediate(function() {
    console.log('immediate1');
    process.nextTick(function() {
        console.log('immediate1_nextTick');
    })
    new Promise(function(resolve) {
        console.log('immediate1_promise');
        resolve();
    }).then(function() {
        console.log('immediate1_then')
    })
})

process.nextTick(function() {
    console.log('glob1_nextTick');
})
new Promise(function(resolve) {
    console.log('glob1_promise');
    resolve();
}).then(function() {
    console.log('glob1_then')
})

setTimeout(function() {
    console.log('timeout2');
    process.nextTick(function() {
        console.log('timeout2_nextTick');
    })
    new Promise(function(resolve) {
        console.log('timeout2_promise');
        resolve();
    }).then(function() {
        console.log('timeout2_then')
    })
})

process.nextTick(function() {
    console.log('glob2_nextTick');
})
new Promise(function(resolve) {
    console.log('glob2_promise');
    resolve();
}).then(function() {
    console.log('glob2_then')
})

setImmediate(function() {
    console.log('immediate2');
    process.nextTick(function() {
        console.log('immediate2_nextTick');
    })
    new Promise(function(resolve) {
        console.log('immediate2_promise');
        resolve();
    }).then(function() {
        console.log('immediate2_then')
    })
})

Node v18.6.0 执行结果:

1
3
5
glob1
glob1_promise
glob2_promise
glob1_nextTick
glob2_nextTick
2
4
undefined 6
glob1_then
glob2_then
7
timeout1
timeout1_promise
timeout1_nextTick
timeout1_then
timeout2
timeout2_promise
timeout2_nextTick
timeout2_then
immediate1
immediate1_promise
immediate1_nextTick
immediate1_then
immediate2
immediate2_promise
immediate2_nextTick
immediate2_then

例题2

(()=>{
    setTimeout(()=>{
        console.log("1-1");
        Promise.resolve().then(()=>{
            console.log("1-2");
        });
    });
    console.log("2-1");
    Promise.resolve().then(()=>{
        console.log("3-1");
        setTimeout(()=>{
            console.log("3-2");
        });
    });
    new Promise(function(reslove) {
        console.log('4-1');
      	setTimeout(() => reslove())
    }).then(function() {
        console.log('4-2');
    })
})()

Chrome  111.0.5563.64 版本执行结果:

2-1
4-1
3-1
1-1
1-2
4-2
3-2

例题3:


console.log("start");

setTimeout(() => {
  console.log("setTimeout1");
}, 0);

(async function foo() {
  console.log("async 1");

  await asyncFunction();

  console.log("async2");

})().then(console.log("foo.then"));

async function asyncFunction() {
  console.log("asyncFunction");

  setTimeout(() => {
    console.log("setTimeout2");
  }, 0);

  new Promise((res) => {
    console.log("promise1");

    res("promise2");
  }).then(console.log);
}

console.log("end");

Chrome 111.0.5563.64 版本执行结果:

start
async 1
asyncFunction
promise1
foo.then
end
promise2
async2
setTimeout1
setTimeout2

例题4:

function double(num) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(2 * num)
        }, 1000)
    })
}

function test1 () {
     const nums = [1, 2, 3];
     nums.forEach(async x => {
         const res = await double(x);
         console.log(res);
     })
}
test1();