JavaScript是单线程
同步与异步:
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval
- micro-task(微任务):Promise,process.nextTick
console.log('执行开始');
setTimeout(() => {
console.log('timeout')
}, 0);
new Promise(function(resolve) {
console.log('进入')
resolve();
}).then(res => console.log('Promise执行完毕') )
console.log('执行结束');
输出:
1.执行开始
2.进入
3.执行结束
4.Promise执行完毕
5.timeout
第一步(先分同步和异步):.整体代码开始执行,首先分为同步和异步,同步按顺序执行,Promise前半部分是同步,then里边的才是异步。
同步 异步
1.console.log('执行开始'); 2.new Promise(function(resolve) { console.log('进入') resolve(); })。(promise前半部分) 3.console.log('执行结束'); |
setTimeout()、Promise后边的then是异步 |
到这里,同步先进入主线程,依次执行完毕,开始处理异步。
上面分出来了同步和异步,同步部分相当于首个宏任务,异步部分需要按照宏任务和微任务的规则执行。上边说明了setTimeout是宏任务,Promise是微任务。
然后可以拆分成这样:
宏任务 微任务
1.console.log('执行开始'); 2.new Promise(function(resolve) { console.log('进入') resolve(); })。(promise前半部分) 3.console.log('执行结束'); |
4.then(res => console.log('Promise执行完毕') ) (Promise后边的then属于微任务) |
setTimeout(() => { console.log('timeout') }, 0); |
执行顺序:
宏任务和微任务相当两个队列(队列先进先出),
区分宏任务和微任务前先要区分同步和异步,同步部分作为首个宏任务压入队列。接下来从上到下从异步中区分宏任务和微任务。
捡值: 1.执行开始,2.进入 3.执行结束 4.Promise执行完毕 5.timeout
再来看一个复杂的:
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. console.log('1'); 2. new Promise(function(resolve) { console.log('7'); resolve(); })
|
4. process.nextTick(function() { console.log('6'); })
5. then(function() { console.log('8') }) |
setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') }) }) | |
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
第一行输出了:1,7,8
第二行:
发现setTimeout里边有宏任务和微任务,剖析第一个setTimeout
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
同步部分(宏任务):
console.log('2');
new Promise(function(resolve) {
console.log('4');
resolve();
})
微任务:
process.nextTick(function() {
console.log('3');
})
then(function() {
console.log('5')
})
})
于是变成:
宏任务 微任务
1. console.log('1'); 2. new Promise(function(resolve) { console.log('7'); resolve(); })
|
4. process.nextTick(function() { console.log('6'); })
5. then(function() { console.log('8') }) |
6.console.log('2'); 7.new Promise(function(resolve) { console.log('4'); resolve(); }) |
8. process.nextTick(function() { console.log('3'); }) 9. then(function() { console.log('5') }) }) |
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
剩下最后一个setTimeout,剖析:
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
同步部分(宏任务):
console.log('9');
new Promise(function(resolve) {
console.log('11');
resolve();
})
微任务:
process.nextTick(function() {
console.log('10');
})
then(function() {
console.log('12')
})
})
于是变成:
宏任务 微任务
1. console.log('1'); 2. new Promise(function(resolve) { console.log('7'); resolve(); })
|
4. process.nextTick(function() { console.log('6'); })
5. then(function() { console.log('8') }) |
6.console.log('2'); 7.new Promise(function(resolve) { console.log('4'); resolve(); }) |
8. process.nextTick(function() { console.log('3'); }) 9. then(function() { console.log('5') }) }) |
10.console.log('9'); 11.new Promise(function(resolve) { console.log('11'); resolve(); }) |
12.process.nextTick(function() { console.log('10'); }) 13.then(function() { console.log('12') }) }) |
执行顺序:
捡值:1,7,6,8,2,4,3,5,9,11,10,12
还有记住一点:从上往下区分。知道如何把代码分成同步异步、从上到下区分宏任务和微任务就知道代码的执行顺序啦!
注意:process.nextTick可能 会因为不同的nodejs版本而导致版本不同。