先上一段面试题:请写出以下代码console的顺序是什么?
你可以先不要看下面的内容,认真的先自己写一遍答案出来,看看自己是否能写出答案来。
setTimeout(() => {
console.log("setTimeOut start");
new Promise((resolve) => {
console.log("promise1 start");
resolve();
}).then(() => {
console.log("promise1 end");
});
console.log("setTimeout end");
}, 0);
function promise2() {
return new Promise((resolve) => {
console.log("promise2");
resolve();
});
}
async function async1() {
console.log("saync1 start");
await promise2();
console.log("saync1 end");
}
async1();
console.log("script end");
现在你可以在你的项目代码script里面把这段代码复制进去执行一下,或者复制到浏览器控制台里运行一下,对一下你的答案是否是正确的。
现在你可以背一个js执行顺序口诀:先同步 后异步 先微观 再宏观
一、js 是单线程执行的
js中的任务按顺序一个一个的执行,但是一个任务耗时太长,那么后面的任务就需要等待,为了解决这种情况,将任务分为了同步任务和异步任务,而异步任务又可以分为微任务和宏任务
二、概念
1.宏任务:当前调用栈中执行的代码成为宏任务。(主代码快,定时器等等)。
2.微任务:当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。(promise.then,proness.nextTick等等)。
3.宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。
三、运行机制
- 在执行栈中执行一个宏任务。
- 执行过程中遇到微任务,将微任务添加到微任务队列中。
- 当前宏任务执行完毕,立即执行微任务队列中的任务。
- 当前微任务队列中的任务执行完毕,检查渲染,GUI线程接管渲染。
- 渲染完毕后,js线程接管,开启下一次事件循环,执行下一次宏任务(事件队列中取)。
四、微任务和宏任务
微任务:process.nextTick、MutationObserver、Promise.then catch finally
宏任务:I/O、setTimeout、setInterval、setImmediate、requestAnimationFrame
五、流程
1、同步和异步任务分别进入不同的执行“场所”,同步进入主线程,异步进入Event Table并注册函数。
2、当指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,回去了Event Queue读取对应的函数,进入主线程。
3、上述过程会不断重复,也就是常说的Event Loop(事件循环)。
4、但是,JS异步还有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入event queue,然后再执行微任务,将微任务放入eventqueue,但是,这两个queue不是一个queue。当你往外拿的时候先从微任务里拿这个回调函数,然后再从宏任务的queue拿宏任务的回调函数。
现在我们来看看我们运行的结果现在是否能理解清楚了
然后运行后的答案就是: