JS单线程意味着它同一时间只能做一件事,所有的任务需要排队。而CPU的处理速度比I/O设备快很多,等待I/O设备是不合理的,所以同步任务在主线程调用栈中调用,异步任务在任务队列中排队。当调用栈清空,就去任务队列里拿一个过来task,反复这个过程。
任务队列
一个Event Loop里可以有多个task queue,一个task queue是一组相同任务源的有序任务的集合。在Event Loop中,每一次循环成为tick,tick中的步骤:
-
拿队列中的第一条任务(macro)task,执行
-
检查是否存在microtasks,如果存在则执行,直至清空microtask queue
-
更新render
-
主线程重复执行上述步骤
注意:task是在主线程的调用栈中执行,任务队列由事件触发线程管理,只要异步任务有运行结果,就在任务队列中放置一个事件;当调用栈所有同步任务执行完毕,系统就会读取任务队列,将可运行的异步任务添加到调用栈中执行
调用栈
每一个进入调用栈的都称为调用帧,调用语句依次压栈
- 堆栈追踪报错
堆栈溢出报错,浏览器会干掉溢出内容
链接: 调用堆栈简述
微任务
Promise.then
Object.observe(废弃)
MutationObserver
process.nextTick(Node.js 环境)
优先级:nextTick>Promise>MutationObserver
宏任务
script(整体代码)
setTimeout // setTimeout与setInternal同源
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)