# All files / src task-loop.ts

75.86% Statements 22/29
66.67% Branches 8/12
77.78% Functions 7/9
75% Lines 21/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129

    7976x
    648x
    648x

    60x
    60x

    15x

    8x
    8x
    8x

    152x
    4x
    4x
    4x

    148x

    140x

    140x

    40x
    40x
    40x

    40x

    40x

     import EventHandler from './event-handler';
    import Hls from './hls';

    /**
     * Sub-class specialization of EventHandler base class.
     *
     * TaskLoop allows to schedule a task function being called (optionnaly repeatedly) on the main loop,
     * scheduled asynchroneously, avoiding recursive calls in the same tick.
     *
     * The task itself is implemented in `doTick`. It can be requested and called for single execution
     * using the `tick` method.
     *
     * It will be assured that the task execution method (`tick`) only gets called once per main loop "tick",
     * no matter how often it gets requested for execution. Execution in further ticks will be scheduled accordingly.
     *
     * If further execution requests have already been scheduled on the next tick, it can be checked with `hasNextTick`,
     * and cancelled with `clearNextTick`.
     *
     * The task can be scheduled as an interval repeatedly with a period as parameter (see `setInterval`, `clearInterval`).
     *
     * Sub-classes need to implement the `doTick` method which will effectively have the task execution routine.
     *
     * Further explanations:
     *
     * The baseclass has a `tick` method that will schedule the doTick call. It may be called synchroneously
     * only for a stack-depth of one. On re-entrant calls, sub-sequent calls are scheduled for next main loop ticks.
     *
     * When the task execution (`tick` method) is called in re-entrant way this is detected and
     * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
     * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
     */

    export default class TaskLoop extends EventHandler {
      private readonly _boundTick: () => void;
      private _tickTimer: number | null = null;
      private _tickInterval: number | null = null;
      private _tickCallCount = 0;

      constructor (hls: Hls, ...events: string[]) {
        super(hls, ...events);
        this._boundTick = this.tick.bind(this);
      }

      /**
       * @override
       */
      protected onHandlerDestroying () {
        // clear all timers before unregistering from event bus
        this.clearNextTick();
        this.clearInterval();
      }

      /**
       * @returns {boolean}
       */
      public hasInterval (): boolean {
        return !!this._tickInterval;
      }

      /**
       * @returns {boolean}
       */
      public hasNextTick (): boolean {
        return !!this._tickTimer;
      }

      /**
       * @param {number} millis Interval time (ms)
       * @returns {boolean} True when interval has been scheduled, false when already scheduled (no effect)
       */
      public setInterval (millis: number): boolean {
        Eif (!this._tickInterval) {
          this._tickInterval = self.setInterval(this._boundTick, millis);
          return true;
        }
        return false;
      }

      /**
       * @returns {boolean} True when interval was cleared, false when none was set (no effect)
       */
      public clearInterval (): boolean {
        if (this._tickInterval) {
          self.clearInterval(this._tickInterval);
          this._tickInterval = null;
          return true;
        }
        return false;
      }

      /**
       * @returns {boolean} True when timeout was cleared, false when none was set (no effect)
       */
      public clearNextTick (): boolean {
        Iif (this._tickTimer) {
          self.clearTimeout(this._tickTimer);
          this._tickTimer = null;
          return true;
        }
        return false;
      }

      /**
       * Will call the subclass doTick implementation in this main loop tick
       * or in the next one (via setTimeout(,0)) in case it has already been called
       * in this tick (in case this is a re-entrant call).
       */
      public tick (): void {
        this._tickCallCount++;
        Eif (this._tickCallCount === 1) {
          this.doTick();
          // re-entrant call to tick from previous doTick call stack
          // -> schedule a call on the next main loop iteration to process this task processing request
          Iif (this._tickCallCount > 1) {
            // make sure only one timer exists at any time at max
            this.clearNextTick();
            this._tickTimer = self.setTimeout(this._boundTick, 0);
          }
          this._tickCallCount = 0;
        }
      }

      /**
       * For subclass to implement task logic
       * @abstract
       */
      protected doTick (): void {}
    }