先综述一下:
浏览器在执行js时有一个渲染主线程, 但是其他IO线程, 网络进程等等也可以向主线程发送一些任务, 必须输入输出, 下载等等, 就引入了消息队列
消息队列中存放的是其他线程和进程发送过来的任务, 每一个任务都是一个宏任务, 浏览器在执行时, 每次从队列首部取出最老的一个任务开始执行
setTimeout异步任务 : 存放在延迟消息队列中, 在浏览器执行完消息队列中的一个最老的任务后, 会取出延迟消息队列中到期的延迟任务, 开始执行. (所以setTimeout可能会有延迟, 不一定到期之后就会立刻被执行)
微任务就是在消息队列中的每个宏任务被执行时, 浏览器都会为其创建该宏任务对应的微任务队列, 宏任务执行完毕会执行其对应的微任务. 所以微任务的执行时间也会影响到宏任务的总体执行时长
下面详细讲述( 浏览器工作原理与实践 的笔记)
消息队列和事件机制
渲染进程下有一个渲染主线程主要来执行任务, 还可以IO线程来添加任务
一个比较好的接收其他线程发送的消息的线程模型就是 - 消息队列
消息队列

流程如下:
- 添加一个消息队列;
- IO 线程中产生的新任务添加进消息队列尾部;
- 渲染主线程会循环地从消息队列头部中读取任务,执行任务。
IO线程也用来接收其他进程发送过来的网络消息, 比如网络资源下载完成等
消息队列中的任务类型
消息队列中的任务类型主要有: 输入事件(鼠标滚动、点击、移动)、微任务、文件读写、WebSocket、JavaScript 定时器等等。
除此之外,消息队列中还包含了很多与页面相关的事件,如 JavaScript 执行、解析 DOM、样式计算、布局计算、CSS 动画等。
以上这些事件都是在主线程中执行的,所以在编写 Web 应用时,你还需要衡量这些事件所占用的时长,并想办法解决单个任务占用主线程过久的问题。
微任务的引入
在消息队列中的所有任务都是单线程的, 必须要等前一个任务完成之后才能去执行下一个任务.
这个时候引入了微任务, 消息队列中的每个任务都是一个宏任务, 每个宏任务都包含一个微任务队列. 如果有高优先级的任务可以放在某个宏任务对应的微任务队列中
setTimeout的实现
setTimeout是一个定时器, 指定多少毫秒之后执行. 如果我们想要执行一段异步任务, 不能立刻将其加入任务队列, 而是要在指定时间之后将其加入到任务队列中
延迟消息队列
在 Chrome 中除了正常使用的消息队列之外,还有另外一个消息队列,这个队列中维护了需要延迟执行的任务列表,包括了定时器和 Chromium 内部一些需要延迟执行的任务。
所以当通过 JavaScript 创建一个定时器时,渲染进程会将该定时器的回调任务添加到延迟队列中
void ProcessTimerTask(){
// 从 delayed_incoming_queue 中取出已经到期的定时器任务
// 依次执行这些任务
}
TaskQueue task_queue;
void ProcessTask();
bool keep_running = true;
void MainTherad(){
for(;;){
// 执行消息队列中的任务
Task task = task_queue.takeTask();
ProcessTask(task);
// 执行延迟队列中的任务
ProcessDelayTask()
if(!keep_running) // 如果设置了退出标志,那么直接退出线程循环
break;
}
}
在上段代码中,处理完消息队列中的一个任务之后,就开始执行 ProcessDelayTask 函数。ProcessDelayTask 函数会根据发起时间和延迟时间计算出到期的任务,然后依次执行这些到期的任务。等到期的任务执行完成之后,再继续下一个循环过程。通过这样的方式,一个完整的定时器就实现了。
setTimeout的问题
当前任务执行时间过久, 影响延迟到期定时器任务的执行
function bar() {
console.log('bar')
}
function foo() {
setTimeout(bar, 0);
for (let i = 0; i < 5000; i++) {
let i = 5+8+8+8
console.log(i)
}
}
foo()
即使setTimeout的延迟时间是0, 但是由于消息队列中的任务for循环执行时间太久会阻碍延迟消息任务的执行, for循环执行大约花费500ms, 所以setTimeout会在500ms后执行
如果 setTimeout 存在嵌套调用,那么系统会设置最短时间间隔为 4 毫秒
function cb() {
setTimeout(cb, 0); }
setTimeout(

最低0.47元/天 解锁文章
324

被折叠的 条评论
为什么被折叠?



