All files / lib/tasks schedule.js

92.59% Statements 75/81
81.81% Branches 9/11
100% Functions 1/1
92.59% Lines 75/81

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 825x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 232x 232x 232x 232x 232x 232x 232x 241x 241x 241x 241x 241x 241x 241x 235x 235x 241x 241x 241x 241x 241x 1x 241x 241x 241x 241x             232x 232x 232x 232x 232x 232x 232x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 226x 226x 226x 226x 226x 226x 232x  
import { StateCache } from '../util/types';
import Transaction from '../transaction';
 
/**
 * If diffHTML is rendering anywhere asynchronously, we need to wait until it
 * completes before this render can be executed. This sets up the next
 * buffer, if necessary, which serves as a Boolean determination later to
 * `bufferSet`.
 *
 * @param {Transaction} transaction
 * @return {Promise<Boolean> | void}
 */
export default function schedule(transaction) {
  // The state is a global store which is shared by all like-transactions.
  let { state, state: { isRendering } } = transaction;
 
  state.measure('schedule');
 
  // Loop through all existing mounts to ensure we properly wait.
  StateCache.forEach(val => {
    const oldMount = /** @type {HTMLElement} */ (
      val.activeTransaction && val.activeTransaction.mount
    );
    const newMount = /** @type {HTMLElement} */ (transaction.mount);
 
    // Only consider transactions that have mounts and are rendering.
    if (!oldMount || !newMount || !val.isRendering) {
      return;
    }
 
    // If the new mount point exists within an existing point that is rendering,
    // then wait for that transaction to finish.
    else if (
      oldMount.contains && oldMount.contains(newMount) ||
      newMount.contains && newMount.contains(oldMount)
    ) {
      state = val;
      isRendering = true;
    }
    // Test if the active transaction is the same as the incoming by looking at
    // the mount. Then look and see if the state is rendering.
    else if (oldMount === newMount) {
      state = val;
      isRendering = true;
    }
  });
 
  const { activeTransaction, nextTransaction } = state;
 
  // If there is an in-flight transaction render happening, push this
  // transaction into a queue.
  if (isRendering) {
    const { tasks } = transaction;
 
    // Pave over the `nextTransaction` to chain off the previous.
    state.nextTransaction = transaction;
 
    // Abort the remaining tasks (but do not signal completion).
    transaction.abort();
 
    const promise = nextTransaction && nextTransaction.promise || activeTransaction.promise || Promise.resolve();
 
    return transaction.promise = promise.then(() => {
      // Mark the transaction as not aborted (we are running it now). This
      // triggers a nested render.
      transaction.aborted = false;
      transaction.state.isRendering = true;
      transaction.state.activeTransaction = transaction;
 
      state.measure('schedule');
 
      return Transaction.flow(transaction, tasks.slice(1));
    });
  }
 
  // Indicate we are now rendering a transaction for this DOM Node.
  state.isRendering = true;
  state.activeTransaction = transaction;
 
  state.measure('schedule');
}