同步任务异步任务
js是一门单线程语言,也就是js任务是一个个执行的,但当某一个任务需要耗费非常多的时间时,后面的任务就会一直等待,造成堵塞。比如新闻页面的中高清图片的加载,我们想要浏览新闻,没有必要等图片加载完成才能阅读接下来的内容。这时候就需要异步任务来模拟多线程任务。
js开始执行,任务进入执行栈,同步任务进入主线程,异步任务进入异步处理模块,完成该任务,并注册回调函数移入任务队列。当同步任务执行完成,便去任务队列读取结果,进入主线程执行,上述过程会不断重复,也就是常说的事件循环。
宏任务微任务
任务可以细分为宏任务和微任务。
宏任务一般包括script,setTimeout,setInterval.
微任务包括promise,process.nextTick.
process.nextTick是nodejs里面的异步任务,是在所有同步任务执行完成时或异步任务开始执行回调函数之前执行的。
事件循环顺序决定js代码的执行顺序。js进入整体代码script,执行宏任务,开始第一次事件循环,当同步任务执行完成,检查是否有可执行的微任务,有则执行所有的微任务,没有则开始新一轮的循环。
经典js面试题分析
console.log('1');
setTimeout(function a() {
console.log('2');
process.nextTick(function() {
console.log('3');
});
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5');
});
}, 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');
});
}, 10);
解析:
- 整体script作为第一个宏任务进入主线程,遇到console.log输出1
- 遇到setTimeout,其回调函数被分发到宏任务队列中,暂且记为setTimeout1
- 遇到process.nextTick,其回调函数被分发到微任务队列
- 遇到promise,new Promise立即执行输出7,回调函数被分发到微任务队列
- 遇到setTimeout,其回调函数被分发到宏任务队列中,记为setTimeout2
- 第一轮事件循环宏任务执行结束,开始执行微任务,process.nextTick, promise回调,输出6,8
- 开始第二轮事件循环,执行setTimeout1, 过程同上, 输出2,4,3,5
- 开始第三轮事件循环,执行setTimeout2, 过程同上,输出9,11,10,12
当两个setTimeout不带参数时, node环境和浏览器环境会有差异