核心有三个:同步事件消息队列,异步事件消息队列,事件循环系统。(后文简称同步队列、延迟队列、事件循环)
浏览器中有一个同步事件消息队列,
所有运行在主线程上的任务,都需要先添加到同步队列,然后事件循环系统再按照先后顺序执行消息队列中的任务。
不考虑异步事件,同步事件的流程如下。
同步队列:
task_queue
sync_task1, sync_task2, sync_task3, ...
事件循环:
getSyncTask; // (sync_task1)
processSyncTask;
getSyncTask; // (sync_task2)
processSyncTask;
getSyncTask; // (sync_task3)
processSyncTask;
引入异步事件的变化是,每次执行完同步任务后,都会去获取异步任务(未必能获取到)
事件循环的流程如下。
同步队列:
task_queue
sync_task1, sync_task2, sync_task3, ...
延迟队列:
delay_task_queue
async_task
事件循环:
getSyncTask; // (sync_task1)
processSyncTask;
getAsyncTask; // 无结果(如延迟时间未到)
getSyncTask; // (sync_task2)
processSyncTask;
getAsyncTask; // (async_task)
processAsyncTask; // 执行异步事件
getSyncTask; // (sync_task3)
processSyncTask;
getAsyncTask; // 无异步事件;
当通过 JavaScript 调用 setTimeout 设置回调函数的时候,渲染进程将会创建一个回调任务,包含了回调函数 name、currentTime、delayTime;
创建好回调任务之后,再将该任务添加到延迟执行队列中;
还要重点关注getAsyncTask以及processAsyncTask的执行时机,在上面的示例中,处理完同步队列中的一个任务之后,就开始执行getAsyncTask 函数。getAsyncTask 函数会根据发起时间和延迟时间计算出到期的任务,然后依次执行这些到期的任务。等到期的任务执行完成之后,再继续下一个循环过程。如果同步任务的时间过久,那异步任务的执行事件未必会远大于设置延迟时间。
同步更新到自己的语雀
https://www.yuque.com/diracke...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。