前端面试题集-------JS事件环机制

面试中经常遇到的JS事件环机制

JS事件环机制:JS的事件分为同步任务和异步任务,遇到同步任务就放在执行栈中执行,遇到异步任务就放进任务队列中,等执行栈中的任务全部执行完成后再去执行任务队列中的任务。
一次事件循环会将所有同步任务及此次循环产生的所有微任务都执行完成。

首先看个例子
setTimeout(() => {console.log(1)}, 400)
console.log(2)
setTimeout(() => {console.log(4)}, 300)
new Promise((r) => {
    console.log(5)
    r(6);
}).then(r => {
    console.log(r)
})
for(let i = 0; i < 100000;i++) {
    console.log('ss')
}
setTimeout(() => {console.log(3)}, 100)
console.log(7)

分析过程:
整个代码执行是宏任务;
1)首先是setTimeout(宏任务),进入任务队列;
2)console是同步任务,输出2;
3)接着又是setTimeout(宏任务),进入任务队列;
4)接下来是promise,promise的构造函数是同步的,所以输出5,then的回调(微任务)进入队列;
5)接下来是for循环,同步执行
6)接下来是settimeout,宏任务,进入任务队列
7)console同步任务,输出7,此时的结果是[2,5, 7],同时执行栈中同步任务已经清空,现在开始执清空任务队列;
8)优先执行微任务promise.then,输出6;
8)虽然第6步中的settimeout延时最短,但是由于for循环阻塞时间较长,所以第1步和第3步的延时任务此时已经执行完成进入队列,所以先输出4、1,最后输出3.
最终结果:[2,5,7,6,4,1,3]。

开头题目答案:
2
5
100000-ss
7
6
4
1
3

setTimeout、setImmediate、process.nextTick、promise.then的执行顺序呢??

// 输出结果可能会根据不同环境出现不同
console.log('golb1');
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');
	});
});

/**
golb1
glob1_promise
glob2_promise
glob1_nextTick
glob2_nextTick
glob1_then
glob2_then
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
 */

综上得出以下几点:
1)macro-task: script (整体代码),setTimeout, setInterval, setImmediate, I/O, UI rendering.
micro-task: process.nextTick, Promise(原生),Object.observe,MutationObserver
2)执行优先级:
同步任务 > 异步任务
process.nextTick > promise.then > setTimeout > setImmediate
3)在执行任务队列中的事件时,会将所有setTimeout以及产生的其他任务执行完再执行setImmediate;process.nextTick和promise.then也适用,会先执行完优先级高的;
4)setTimeout计时开始的时间是从代码执行到开始的,计时结束后回调函数进入队列,所以如果有耗时比较长的同步任务A,A之前的延时长的会比A之后延时短的异步任务先执行。(个人见解,大家有不同意见可以指教)
5)任务队列中存储的是异步事件的回调函数,而不是整个异步事件

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值