tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

batching.js (3243B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  BATCH_ACTIONS,
      9  BATCH_ENABLE,
     10  BATCH_RESET,
     11  BATCH_FLUSH,
     12 } = require("resource://devtools/client/netmonitor/src/constants.js");
     13 
     14 const REQUESTS_REFRESH_RATE = 50; // ms
     15 
     16 /**
     17 * Middleware that watches for actions with a "batch = true" value in their meta field.
     18 * These actions are queued and dispatched as one batch after a timeout.
     19 * Special actions that are handled by this middleware:
     20 * - BATCH_ENABLE can be used to enable and disable the batching.
     21 * - BATCH_RESET discards the actions that are currently in the queue.
     22 */
     23 function batchingMiddleware() {
     24  return next => {
     25    let queuedActions = [];
     26    let enabled = true;
     27    let flushTask = null;
     28 
     29    return action => {
     30      if (action.type === BATCH_ENABLE) {
     31        return setEnabled(action.enabled);
     32      }
     33 
     34      if (action.type === BATCH_RESET) {
     35        return resetQueue();
     36      }
     37 
     38      if (action.type === BATCH_FLUSH) {
     39        return flushQueue();
     40      }
     41 
     42      if (action.meta?.batch) {
     43        if (!enabled) {
     44          next(action);
     45          return Promise.resolve();
     46        }
     47 
     48        queuedActions.push(action);
     49 
     50        if (!flushTask) {
     51          flushTask = new DelayedTask(flushActions, REQUESTS_REFRESH_RATE);
     52        }
     53 
     54        return flushTask.promise;
     55      }
     56 
     57      return next(action);
     58    };
     59 
     60    function setEnabled(value) {
     61      enabled = value;
     62 
     63      // If disabling the batching, flush the actions that have been queued so far
     64      if (!enabled && flushTask) {
     65        flushTask.runNow();
     66      }
     67    }
     68 
     69    function resetQueue() {
     70      queuedActions = [];
     71 
     72      if (flushTask) {
     73        flushTask.cancel();
     74        flushTask = null;
     75      }
     76    }
     77 
     78    function flushQueue() {
     79      if (flushTask) {
     80        flushTask.runNow();
     81      }
     82    }
     83 
     84    function flushActions() {
     85      const actions = queuedActions;
     86      queuedActions = [];
     87 
     88      next({
     89        type: BATCH_ACTIONS,
     90        actions,
     91      });
     92 
     93      flushTask = null;
     94    }
     95  };
     96 }
     97 
     98 /**
     99 * Create a delayed task that calls the specified task function after a delay.
    100 */
    101 class DelayedTask {
    102  #promise;
    103  constructor(taskFn, delay) {
    104    this.#promise = new Promise((resolve, reject) => {
    105      this.runTask = cancel => {
    106        if (cancel) {
    107          reject("Task cancelled");
    108        } else {
    109          taskFn();
    110          resolve();
    111        }
    112        this.runTask = null;
    113      };
    114      this.timeout = setTimeout(this.runTask, delay);
    115    }).catch(console.error);
    116  }
    117  /**
    118   * Return a promise that is resolved after the task is performed or canceled.
    119   */
    120  get promise() {
    121    return this.#promise;
    122  }
    123 
    124  /**
    125   * Cancel the execution of the task.
    126   */
    127  cancel() {
    128    clearTimeout(this.timeout);
    129    if (this.runTask) {
    130      this.runTask(true);
    131    }
    132  }
    133 
    134  /**
    135   * Execute the scheduled task immediately, without waiting for the timeout.
    136   * Resolves the promise correctly.
    137   */
    138  runNow() {
    139    clearTimeout(this.timeout);
    140    if (this.runTask) {
    141      this.runTask();
    142    }
    143  }
    144 }
    145 
    146 module.exports = batchingMiddleware;