关于事件循环
主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制,又称为Event Loop (事件循环)。
关于执行栈
当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。这个过程反复进行,直到执行栈中的代码全部执行完毕。
- 当代码执行的时候,同步代码按照执行顺序开始执行
- 当代码执行的时候,碰到函数,引擎会在栈里产生这个函数执行栈,也叫执行上下文。
- 当代码执行到函数的时候,会进入这个执行环境继续执行其中的代码,反复进行,全部执行完
关于任务队列
- 微任务队列(micro tasks)只会有一个
- 宏任务队列(macro tasks)可以有多个
- click ajax 等回调方法都会进入到宏任务队列(macro tasks)中,当然也包括上面的
- 宏任务按顺序执行,且浏览器在每个宏任务之间渲染页面
- 所有微任务也按顺序执行,且在以下场景会立即执行所有微任务
- 每个回调之后且js执行栈中为空。
- 每个宏任务结束后。
关于Nodejs事件循环机制过程
NodeJs 的运行是这样的:
- 初始化 Event Loop
- 执行您的主代码。这里同样,遇到异步处理,就会分配给对应的队列。直到主代码执行完毕。
- 执行主代码中出现的所有微任务:先执行完所有nextTick(),然后在执行其它所有微任务。
- 开始 Event Loop
- 当每个阶段执行完毕后,都会执行所有微任务(先 nextTick,后其它),然后再进入下一个阶段。
自己的小总结
- 宏任务->微任务->宏任务中的微任务
例题
async function b() {
console.log('b');
await c();
console.log('b1');
}
async function c() {
console.log('c');
await new Promise(function(resolve, reject) {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise1-1');
});
setTimeout(() => {
console.log('settimeout1');
});
console.log('c1');
}
new Promise(function(resolve, reject) {
console.log('promise2');
resolve();
console.log('promise2-1');
reject();
}).then(() => {
console.log('promise2-2');
setTimeout(() => {
console.log('settimeout2');
new Promise(function(resolve, reject) {
resolve();
}).then(function() {
console.log('?');
});
});
}).catch(() => {
console.log('promise-reject');
});
console.log('200');
b();
运行结果:
promise2
promise2-1
200
b
c
promise1
promise2-2
promise1-1
c1
b1
settimeout2
?
settimeout1
参考文章
js 异步、栈、事件循环、任务队列
微任务、宏任务、立即执行函数(async await)
浏览器内核机制、JS事件循环、Promise、Task、事件冒泡、事件委托详解
强推该博客,可以看到整个过程是怎样执行的