js中异步回调函数的执行机制与事件循环
先理解几个核心概念
1、调用栈:同步代码会按照顺序进入调用栈执行
2、任务队列:所有异步回调函数,(包括setTimeOut,DOM,Promise等)都会被放入任务队列等待执行
3、事件循环:他的工作就是不断检查调用栈是否为空,如果为空,就会从任务队列中取出第一个任务放到调用栈中执行
举个例子:
setTimeOut的延迟事件是1s,但是同步代码的执行需要2s,此时1s后调用栈仍然不为空,定时器的回调函数 fn 会一直在任务队列中等待,只有调用栈完全清空,事件循环才会将任务队列中的回调函数fn放入调用栈执行
console.log('开始');// 同步代码,需要2秒执行
const start = Date.now();
while (Date.now() - start < 2000) {// 模拟耗时操作
}// 异步代码,设置1秒后执行
setTimeout(() => {console.log('setTimeout执行');
}, 1000);console.log('结束');
执行顺序是:
- 立即打印 "开始"
- 执行 2 秒的同步循环
- 打印 "结束"
- 此时调用栈为空,事件循环发现任务队列中有
setTimeout
回调 - 执行回调,打印 "setTimeout 执行"
虽然 setTimeout
指定了 1 秒后执行,但实际上它会在 2 秒多后才执行,因为需要等待前面的同步代码完成。