Timer
JSTimer.js
setTimeout
setTimeout
- 调用_allocateCallback函数,返回一个全局的callbackID
- _allocateCallback首先生成一个id,为GUID++(初始值为1),用timerIDs保存id,callbacks保存func,types保存type(见JSTimerType,为setTimeout string),三者保存的数组index相同
- 调用createTimer函数,传入callbackID,这里调用NativeTiming的createTimer
- Native在触发timer 函数时会调用callTimers,传入callbackID数组,这里分别调用_callTimer
- 从timerIDs里面取出callbackID对应的timerIndex
- 然后根据index取出callbacks内的callback进行调用
RCTTiming Native部分见RCTTiming类
整个RCTTiming只有一个不重复NSTimer控制所有的JS 计时器,NSTimer interval设置为0,一帧后触发,通过不断调整fireDate来触发fire的时间,fireDate为所有JS 计时器的时间按序排列依次触发。
createTimer函数,主要调用createTimerForNextFrame
- 创建一个_RCTTimer模型对象,传入callbackID、duration、targetTime(fire的时间戳)等
- _timers map保存该timer,key为callbackID,value为_RCTTimer对象
- 接着会判断background,进行后台后调用的是scheduleSleepTimer
- 接着判断paused,paused设置为yes的触发逻辑:stopTimers,设置为no的触发逻辑:startTimers
- 调用scheduleSleepTimer(处于后台、或paused为yes且timer触发时间在1s以后,否则调用startTimers)
- 初始化NSTimer,interval为0,repeat为no,并加入runloop(1帧之后调用)
- 回调在timerDidFire函数,若paused为yes则调用startTimers和didUpdateFrame,这里调用didUpdateFrame,这里最终会调用JSTimer的callTimers函数,传入参数为callbackID
- startTimers的逻辑就是把paused设置为no
didUpdateFrame 函数逻辑
- 从timers map里面取出timer,判断是否需要fire,需要则加入timersToCall数组
- 从timersToCall数组取出callbackId,调用JS的JSTimers的callTimers方法,传入callbackID数组作为参数
- timersToCall遍历,如果repeat为no则删除timers里的对应timer。如果为yes,调用reschedule重新计算下一次的fire时间
- 获取剩余timers个数
- 若后台,则调用scheduleSleepTimer,入参为所有timer中的下一个时间的Date对象
- 其他则_paused设置为yes,调用scheduleSleepTimer
didUpdateFrame的触发逻辑
- _jsThreadUpdate调用的时候,也就是js线程 CADisplayLink回调
- 若paused为no,则出发didUpdateFrame
- timerDidFire fire的时候
- 进入后台的时候
requestAnimationFrame
requestAnimationFrame为特殊的setTimeout,不同的是固定的duration为1ms
requestIdleCallback
requestIdleCallback
- 若无idle任务,则setSendIdleEvents为true
- 调用_allocateCallback
- requestIdleCallbacks push callbackID
callIdleCallbacks
- 遍历requestIdleCallbacks,调用_callTimer函数
- 若遍历完成,没有新增idle,调用setSendIdleEvents设置为false,这里会调用Native的setSendIdleEvents
- 在native setSendIdleEvents,true则调用startTimers,否则若无pending timers则stopTimers
Native调用callIdleCallbacks的流程
主要还是在didUpdateFrame部分
- 判断整个didUpdateFrame的执行时间小于一帧时间,则进入native调用js callback
- 通过bridge调用JSTimers的callIdleCallbacks
queueReactNativeMicrotask
RN的microtask机制,也是作为setImmediate的实现
queueReactNativeMicrotask
- 依然首先调用_allocateCallback获取callbackID
- reactNativeMicrotasks push 返回的id
callReactNativeMicrotasks
callReactNativeMicrotasks这里会调用_callReactNativeMicrotasksPass,取出任务,依次调用_callTimer触发callback
在JSTimers.js里会设置microtask的callback,如下
BatchedBridge.setReactNativeMicrotasksCallback(
JSTimers.callReactNativeMicrotasks,
);
callback的触发机制
MessageQueue.js的flushedQueue会触发callback,而在每次callFunctionReturnFlushedQueue和invokeCallbackAndReturnFlushedQueue都会调用flushedQueue