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

results matching ""

    No results matching ""