- 现象:计时器计时严重不准
- 场景描述:
**setTimeout(200, cb)**
期待的效果是延迟 200ms 之后,调用 cb 函数,可是实际上延迟的间隔,远不止 200ms,延迟的时间甚至可能会远超 1s。 - 分析:在项目中,使用到了 cpp 给 node 封装的一些 addon,是使用 napi 来实现的封装。每当调用 cpp 提供的 native api 时,往往会阻塞 JS 的主线程。当主线程阻塞的过于严重时,同步任务始终没能结束,于是通过
setTimeout
添加到任务队列中的宏任务始终没能被取出来执行,同步任务耗时越长,任务队列中的计时任务实际被执行时的时间就越靠后。 - 解决方案 1:将计时任务丢给 cpp 做。
如果 cb 任务恰好是调用 cpp 提供的 addon 的一个 api 的话,那么这个任务的耗时可以丢给 cpp 去实现,这意味着需要 cpp 提供的这个 api 新增一个参数,这个参数代表延迟的时间。因为项目上遇到的交互场景恰好可用,于是采用的是这种方案来实现,实测下来效果还不错。 - 解决方案 2:及时任务丢给子线程去做。
JS 的主线程在执行 cpu 密集型操作时,导致事件循环中的异步任务无法按照预期的时间来取出执行,虽然主线程阻塞了,导致计时不准,那么可以开子线程来处理一些 cpu 密集型任务,让主进程的事件循环机制“恢复正常”。没有实际应用过,不过这种方案应该是可行的,需要注意的是线程的管理。