[JS] setTimeout的异步操作如何实现

DiracKeeko

核心有三个:同步事件消息队列,异步事件消息队列,事件循环系统。(后文简称同步队列、延迟队列、事件循环)

浏览器中有一个同步事件消息队列,
所有运行在主线程上的任务,都需要先添加到同步队列,然后事件循环系统再按照先后顺序执行消息队列中的任务。

不考虑异步事件,同步事件的流程如下。

同步队列:
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...

阅读 145
10 声望
0 粉丝
0 条评论
你知道吗?

10 声望
0 粉丝
文章目录
宣传栏