经典面试题
如果你知道以下代码输出结果,出门左拐,不送,如果你不懂,你需要认认真真的看。
process.nextTick
必须在nodejs中执行
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');
})
async function fn() {
await fn2();
console.log(13);
}
function fn2() {
console.log(14);
}
fn()
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')
})
})
javascript事件循环
既然js是单线程,那就像只有一个窗口的银行,客户需要排队一个一个办理业务,同理js任务也要一个一个顺序执行。如果一个任务耗时过长,那么后一个任务也必须等着。那么问题来了,假如我们想浏览新闻,但是新闻包含的超清图片加载很慢,难道我们的网页要一直卡着直到图片完全显示出来?因此聪明的程序员将任务分为两类:
同步任务
异步任务
同步任务和异步任务
你以为的js是不是下边这样。123
console.log(1);
setTimeout(() => {
console.log(2);
},0)
console.log(3);
你错了 ,他的结果是132;
首先你要明白什么是同步和异步。
同步
大家都知道js代码从上而下执行,同步的操作有以下几个
console.log
语句- 函数声明
- 函数调用
- 实例化对象;
- 但是需要记住.
prompt
和confirm
和alert
都会阻塞代码的执行。
阻塞不是异步是直接中断代码的执行。
异步操作
异步操作会等待所有的同步操作执行完成以后才会执行异步操作
我们进入正题,除了广义的同步任务和异步任务,我们对任务有更精细的定义:
macro-task(宏任务):包括整体代码script
,setTimeout
,setInterval
micro-task(微任务):Promise
,process.nextTick
,await
分析面试题
console.log('开启成功');
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');
})
async function fn() {
await fn2();
console.log(13);
}
function fn2() {
console.log(14);
}
fn()
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')
})
})
- 找出所有的同步操作和异步操作
console.log('1');
刚才说过,调用函数也属于同步,所有调用了fn()
执行
async function fn() {
await fn2();
console.log(13);
}
因为fn属于async函数,所以会先执行await这一行的代码,但不会async函数中的await下一行的代码
所以执行调用fn2执行
console.log(14);
然后执行promise实例化对象中的
console.log('7');
此时此刻都属于同步操作
- 执行异步操作
异步分为宏任务与微任务
setTimeout
宏任务放到最后执行
现在其中有三个微任务
process.nextTick(function() {
console.log('6');
})
async function fn() {
await fn2();
console.log(13);
}
.then(function() {
console.log('8')
})
按照代码执行的先后顺序,先执行
console.log('6');
因为fn()的函数调用在实例化promise之前,所以先执行
console.log(13);
最后执行
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')
})
})
还是一样的逻辑
上面的输出 2 ,4在计时器中属于同步,先执行。
然后执行微任务 3,5
面试题输出结果为
1 14 7 6 13 8 2 4 3 5 9 11 10 12
把fn()
放在实例化promise
之后你还会吗.