text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   *
   */
  
  /* eslint-disable no-var */
  
  // TODO: Use symbols?
  var ImmediatePriority = 1;
  var UserBlockingPriority = 2;
  var NormalPriority = 3;
  var IdlePriority = 4;
  
  // Max 31 bit integer. The max integer size in V8 for 32-bit systems.
  // Math.pow(2, 30) - 1
  // 0b111111111111111111111111111111
  var maxSigned31BitInt = 1073741823;
  
  // Times out immediately
  var IMMEDIATE_PRIORITY_TIMEOUT = -1;
  // Eventually times out
  var USER_BLOCKING_PRIORITY = 250;
  var NORMAL_PRIORITY_TIMEOUT = 5000;
  // Never times out
  var IDLE_PRIORITY = maxSigned31BitInt;
  
  // Callbacks are stored as a circular, doubly linked list.
  var firstCallbackNode = null;
  
  var currentPriorityLevel = NormalPriority;
  var currentEventStartTime = -1;
  var currentExpirationTime = -1;
  
  // This is set when a callback is being executed, to prevent re-entrancy.
  var isExecutingCallback = false;
  
  var isHostCallbackScheduled = false;
  
  var hasNativePerformanceNow =
    typeof performance === 'object' && typeof performance.now === 'function';
  
  var timeRemaining;
  if (hasNativePerformanceNow) {
    timeRemaining = function() {
      if (
        firstCallbackNode !== null &&
        firstCallbackNode.expirationTime < currentExpirationTime
      ) {
        // A higher priority callback was scheduled. Yield so we can switch to
        // working on that.
        return 0;
      }
      // We assume that if we have a performance timer that the rAF callback
      // gets a performance timer value. Not sure if this is always true.
      var remaining = getFrameDeadline() - performance.now();
      //getFrameDeadline() ===>>  frameDeadline = rafTime + activeFrameTime
      return remaining > 0 ? remaining : 0;
      // 这帧的渲染时间  是否超时
    };
  } else {
    timeRemaining = function() {
      // Fallback to Date.now()
      if (
        firstCallbackNode !== null &&
        firstCallbackNode.expirationTime < currentExpirationTime
      ) {
        return 0;
      }
      var remaining = getFrameDeadline() - Date.now();
      return remaining > 0 ? remaining : 0;
    };
  }
  
  var deadlineObject = {
    timeRemaining,
    didTimeout: false,
  };
  
  function ensureHostCallbackIsScheduled() {
    if (isExecutingCallback) {
      //表示已经有callback被调用了
      // Don't schedule work yet; wait until the next time we yield.
      return;
    }
    // Schedule the host callback using the earliest expiration in the list.
    var expirationTime = firstCallbackNode.expirationTime;
    //获取的时候最高优先级的
    if (!isHostCallbackScheduled) {
      //这个callback有没有进入调度
      //没有调度就设置为true
      isHostCallbackScheduled = true;
    } else {
      // Cancel the existing host callback.
      //有了的话, 取消之前的callback
      cancelHostCallback();
    }
    requestHostCallback(flushWork, expirationTime);
  }
  
  function flushFirstCallback() {
    var flushedNode = firstCallbackNode;
  
    // Remove the node from the list before calling the callback. That way the
    // list is in a consistent state even if the callback throws.
    var next = firstCallbackNode.next;
    if (firstCallbackNode === next) {
      //只有一个节点
      // This is the last callback in the list.
      firstCallbackNode = null;
      next = null;
    } else {
      var lastCallbackNode = firstCallbackNode.previous;
      firstCallbackNode = lastCallbackNode.next = next;
      next.previous = lastCallbackNode;
    }
  
    flushedNode.next = flushedNode.previous = null;
  
    // Now it's safe to call the callback.
    var callback = flushedNode.callback;
    var expirationTime = flushedNode.expirationTime;
    var priorityLevel = flushedNode.priorityLevel;
    var previousPriorityLevel = currentPriorityLevel;
    var previousExpirationTime = currentExpirationTime;
    currentPriorityLevel = priorityLevel;
    currentExpirationTime = expirationTime;
    var continuationCallback;
    try {
      continuationCallback = callback(deadlineObject);
    } finally {
      currentPriorityLevel = previousPriorityLevel;
      currentExpirationTime = previousExpirationTime;
    }
  
    // A callback may return a continuation. The continuation should be scheduled
    // with the same priority and expiration as the just-finished callback.
    if (typeof continuationCallback === 'function') {
      var continuationNode: CallbackNode = {
        callback: continuationCallback,
        priorityLevel,
        expirationTime,
        next: null,
        previous: null,
      };
  
      // Insert the new callback into the list, sorted by its expiration. This is
      // almost the same as the code in `scheduleCallback`, except the callback
      // is inserted into the list *before* callbacks of equal expiration instead
      // of after.
      if (firstCallbackNode === null) {
        // This is the first callback in the list.
        firstCallbackNode = continuationNode.next = continuationNode.previous = continuationNode;
      } else {
        var nextAfterContinuation = null;
        var node = firstCallbackNode;
        do {
          if (node.expirationTime >= expirationTime) {
            // This callback expires at or after the continuation. We will insert
            // the continuation *before* this callback.
            nextAfterContinuation = node;
            break;
          }
          node = node.next;
        } while (node !== firstCallbackNode);
  
        if (nextAfterContinuation === null) {
          // No equal or lower priority callback was found, which means the new
          // callback is the lowest priority callback in the list.
          nextAfterContinuation = firstCallbackNode;
        } else if (nextAfterContinuation === firstCallbackNode) {
          // The new callback is the highest priority callback in the list.
          firstCallbackNode = continuationNode;
          ensureHostCallbackIsScheduled();
        }
  
        var previous = nextAfterContinuation.previous;
        previous.next = nextAfterContinuation.previous = continuationNode;
        continuationNode.next = nextAfterContinuation;
        continuationNode.previous = previous;
      }
    }
  }
  
  function flushImmediateWork() {
    if (
      // Confirm we've exited the outer most event handler
      currentEventStartTime === -1 &&
      firstCallbackNode !== null &&
      firstCallbackNode.priorityLevel === ImmediatePriority
    ) {
      isExecutingCallback = true;
      deadlineObject.didTimeout = true;
      try {
        do {
          flushFirstCallback(); //执行callback链表, 直到第一个不过期的任务为止
        } while (
          // Keep flushing until there are no more immediate callbacks
          firstCallbackNode !== null &&
          firstCallbackNode.priorityLevel === ImmediatePriority
        );
      } finally {
        isExecutingCallback = false;
        if (firstCallbackNode !== null) {
          // There's still work remaining. Request another callback.
          ensureHostCallbackIsScheduled();
        } else {
          isHostCallbackScheduled = false;
        }
      }
    }
  }
  
  function flushWork(didTimeout) {
    isExecutingCallback = true;//调用过之后 设置为true
    deadlineObject.didTimeout = didTimeout;
    // deadlineObject = {
    //   timeRemaining:判断有没有剩余时间
    //   didTimeout,
    // }
    try {
      if (didTimeout) {
        //这种情况是有任务过期了
        // Flush all the expired callbacks without yielding.
        while (firstCallbackNode !== null) {
          // Read the current time. Flush all the callbacks that expire at or
          // earlier than that time. Then read the current time again and repeat.
          // This optimizes for as few performance.now calls as possible.
          var currentTime = getCurrentTime();
          if (firstCallbackNode.expirationTime <= currentTime) {
            //执行callback链表 直到第一个 不过期的任务为止
            do {
              flushFirstCallback();
            } while (
              firstCallbackNode !== null &&
              firstCallbackNode.expirationTime <= currentTime
            );
            continue;
          }
          break;
        }
      } else {
        //didTimeout => false   没有任务过期
        // Keep flu
        //任务没有过期
        if (firstCallbackNode !== null) {
          do {
            flushFirstCallback();
          } while (
            firstCallbackNode !== null &&
            getFrameDeadline() - getCurrentTime() > 0
            //getFrameDeadline() - getCurrentTime() > 0 这一帧 还有剩余时间
          );
        }
      }
    } finally {
      isExecutingCallback = false;
      if (firstCallbackNode !== null) {
        // There's still work remaining. Request another callback.
        ensureHostCallbackIsScheduled();
      } else {
        isHostCallbackScheduled = false;
      }
      // Before exiting, flush all the immediate work that was scheduled.
      flushImmediateWork();
    }
  }
  
  function unstable_runWithPriority(priorityLevel, eventHandler) {
    switch (priorityLevel) {
      case ImmediatePriority:
      case UserBlockingPriority:
      case NormalPriority:
      case IdlePriority:
        break;
      default:
        priorityLevel = NormalPriority;
    }
  
    var previousPriorityLevel = currentPriorityLevel;
    var previousEventStartTime = currentEventStartTime;
    currentPriorityLevel = priorityLevel;
    currentEventStartTime = getCurrentTime();
  
    try {
      return eventHandler();
    } finally {
      currentPriorityLevel = previousPriorityLevel;
      currentEventStartTime = previousEventStartTime;
  
      // Before exiting, flush all the immediate work that was scheduled.
      flushImmediateWork();
    }
  }
  
  function unstable_wrapCallback(callback) {
    var parentPriorityLevel = currentPriorityLevel;
    return function() {
      // This is a fork of runWithPriority, inlined for performance.
      var previousPriorityLevel = currentPriorityLevel;
      var previousEventStartTime = currentEventStartTime;
      currentPriorityLevel = parentPriorityLevel;
      currentEventStartTime = getCurrentTime();
  
      try {
        return callback.apply(this, arguments);
      } finally {
        currentPriorityLevel = previousPriorityLevel;
        currentEventStartTime = previousEventStartTime;
        flushImmediateWork();
      }
    };
  }
  
  function unstable_scheduleCallback(callback, deprecated_options) {
    //1、创建一个任务节点newNode，按照优先级插入callback链表
    //2,我们把任务按照过期时间排好顺序了，那么何时去执行任务呢？怎么去执行呢？答案是有两种情况
    //1是当添加第一个任务节点的时候开始启动任务执行，
    //2是当新添加的任务取代之前的节点成为新的第一个节点的时候。因为1意味着任务从无到有，应该 立刻启动。
    //2意味着来了新的优先级最高的任务，应该停止掉之前要执行的任务，重新从新的任务开始执行
    //上面两种情况就对应ensureHostCallbackIsScheduled方法执行的两种情况。
    //
    var startTime =
      currentEventStartTime !== -1 ? currentEventStartTime : getCurrentTime();
    //getCurrentTime() ===> date.now
    //startTime = date.now()
    var expirationTime;
    if (
      typeof deprecated_options === 'object' &&
      deprecated_options !== null &&
      typeof deprecated_options.timeout === 'number'
    ) {
      // FIXME: Remove this branch once we lift expiration times out of React.
      // 这里其实只会进第一个 if 条件，因为外部写死了一定会传 deprecated_options.timeout
    // 越小优先级越高，同时也代表一个任务的过期时间
      expirationTime = startTime + deprecated_options.timeout;
    } else {
      switch (currentPriorityLevel) {
        case ImmediatePriority:
          expirationTime = startTime + IMMEDIATE_PRIORITY_TIMEOUT;
          break;
        case UserBlockingPriority:
          expirationTime = startTime + USER_BLOCKING_PRIORITY;
          break;
        case IdlePriority:
          expirationTime = startTime + IDLE_PRIORITY;
          break;
        case NormalPriority:
        default:
          expirationTime = startTime + NORMAL_PRIORITY_TIMEOUT;
      }
    }
  // 环形双向链表结构
    var newNode = {
      callback,
      priorityLevel: currentPriorityLevel,
      expirationTime,
      next: null,
      previous: null,
    };
  
    // Insert the new callback into the list, ordered first by expiration, then
    // by insertion. So the new callback is inserted any other callback with
    // equal expiration.
    // 核心思路就是 firstCallbackNode 优先级最高 lastCallbackNode 优先级最低
    // 新生成一个 newNode 以后，就从头开始比较优先级
    // 如果新的高，就把新的往前插入，否则就往后插，直到没有一个 node 的优先级比他低
    // 那么新的节点就变成 lastCallbackNode
    // 在改变了firstCallbackNode的情况下，需要重新调度
    if (firstCallbackNode === null) {
      // firstCallbackNode 是react维护单向链表的头部，第一个
      // This is the first callback in the list.
      firstCallbackNode = newNode.next = newNode.previous = newNode;
      ensureHostCallbackIsScheduled();
    } else {
      //链表有值
      var next = null;
      var node = firstCallbackNode;//队首
      do {
        if (node.expirationTime > expirationTime) {
          //如果当前优先级低于expirationTime, 把下一个赋值能当前的node
          //优先级从高到低排序
          //如果node.expirationTime 都比 当前传入的expirationTime大, 
          //证明当前传入的expirationTime优先级是比对首的优先级还高
          //next = 优先级高的
          next = node;
          break;
        }
        node = node.next;
      } while (node !== firstCallbackNode);
  
      if (next === null) {
        //next === null  证明当前传入cb, 优先级是最低的 因此next 还是当前的队首
        next = firstCallbackNode;
        //插在最后面
      } else if (next === firstCallbackNode) {
        // The new callback has the earliest expiration in the entire list.
        firstCallbackNode = newNode;
        // 插在最前面   优先级最高
        ensureHostCallbackIsScheduled();
        //相当于 reset
      }
  
      var previous = next.previous;
      previous.next = next.previous = newNode;
      newNode.next = next;
      newNode.previous = previous;
    }
  
    return newNode;
  }
  
  function unstable_cancelCallback(callbackNode) {
    var next = callbackNode.next;
    if (next === null) {
      // Already cancelled.
      return;
    }
  
    if (next === callbackNode) {
      // This is the only scheduled callback. Clear the list.
      firstCallbackNode = null;
    } else {
      // Remove the callback from its position in the list.
      if (callbackNode === firstCallbackNode) {
        firstCallbackNode = next;
      }
      var previous = callbackNode.previous;
      previous.next = next;
      next.previous = previous;
    }
  
    callbackNode.next = callbackNode.previous = null;
  }
  
  function unstable_getCurrentPriorityLevel() {
    return currentPriorityLevel;
  }
  
  // The remaining code is essentially a polyfill for requestIdleCallback. It
  // works by scheduling a requestAnimationFrame, storing the time for the start
  // of the frame, then scheduling a postMessage which gets scheduled after paint.
  // Within the postMessage handler do as much work as possible until time + frame
  // rate. By separating the idle call into a separate event tick we ensure that
  // layout, paint and other browser work is counted against the available time.
  // The frame rate is dynamically adjusted.
  
  // We capture a local reference to any global, in case it gets polyfilled after
  // this module is initially evaluated. We want to be using a
  // consistent implementation.
  var localDate = Date;
  
  // This initialization code may run even on server environments if a component
  // just imports ReactDOM (e.g. for findDOMNode). Some environments might not
  // have setTimeout or clearTimeout. However, we always expect them to be defined
  // on the client. https://github.com/facebook/react/pull/13088
  var localSetTimeout = typeof setTimeout === 'function' ? setTimeout : undefined;
  var localClearTimeout =
    typeof clearTimeout === 'function' ? clearTimeout : undefined;
  
  // We don't expect either of these to necessarily be defined, but we will error
  // later if they are missing on the client.
  var localRequestAnimationFrame =
    typeof requestAnimationFrame === 'function'
      ? requestAnimationFrame
      : undefined;
  var localCancelAnimationFrame =
    typeof cancelAnimationFrame === 'function' ? cancelAnimationFrame : undefined;
  
  var getCurrentTime;
  
  // requestAnimationFrame does not run when the tab is in the background. If
  // we're backgrounded we prefer for that work to happen so that the page
  // continues to load in the background. So we also schedule a 'setTimeout' as
  // a fallback.
  // TODO: Need a better heuristic for backgrounded work.
  var ANIMATION_FRAME_TIMEOUT = 100;
  var rAFID;
  var rAFTimeoutID;
  var requestAnimationFrameWithTimeout = function(callback) {
    // schedule rAF and also a setTimeout
    rAFID = localRequestAnimationFrame(function(timestamp) {
      // cancel the setTimeout
      localClearTimeout(rAFTimeoutID); //清除定时器
      callback(timestamp); //执行回调
    });
    rAFTimeoutID = localSetTimeout(function() { 
      //防止 requestAnimation 太长时间没被调用
      //如果  100ms 内没有被调用 取消, 需要立即调用callback
      // cancel the requestAnimationFrame
      localCancelAnimationFrame(rAFID);
      callback(getCurrentTime());
    }, ANIMATION_FRAME_TIMEOUT);
  };
  
  if (hasNativePerformanceNow) {
    var Performance = performance;
    getCurrentTime = function() {
      return Performance.now();
    };
  } else {
    getCurrentTime = function() {
      return localDate.now();
    };
  }
  
  var requestHostCallback;
  var cancelHostCallback;
  var getFrameDeadline;
  
  if (typeof window !== 'undefined' && window._schedMock) {
    // Dynamic injection, only for testing purposes.
    var impl = window._schedMock;
    requestHostCallback = impl[0];
    cancelHostCallback = impl[1];
    getFrameDeadline = impl[2];
  } else if (
    // If Scheduler runs in a non-DOM environment, it falls back to a naive
    // implementation using setTimeout.
    typeof window === 'undefined' ||
    // "addEventListener" might not be available on the window object
    // if this is a mocked "window" object. So we need to validate that too.
    //当前不处于浏览器环境
    typeof window.addEventListener !== 'function'
  ) {
    var _callback = null;
    var _currentTime = -1;
    var _flushCallback = function(didTimeout, ms) {
      if (_callback !== null) {
        var cb = _callback;
        _callback = null;
        try {
          _currentTime = ms;
          cb(didTimeout);
        } finally {
          _currentTime = -1;
        }
      }
    };
    requestHostCallback = function(cb, ms) {
      if (_currentTime !== -1) {
        // Protect against re-entrancy.
        setTimeout(requestHostCallback, 0, cb, ms);
      } else {
        _callback = cb;
        setTimeout(_flushCallback, ms, true, ms);
        setTimeout(_flushCallback, maxSigned31BitInt, false, maxSigned31BitInt);
      }
    };
    cancelHostCallback = function() {
      _callback = null;
    };
    getFrameDeadline = function() {
      return Infinity;
    };
    getCurrentTime = function() {
      return _currentTime === -1 ? 0 : _currentTime;
    };
  } else {
    if (typeof console !== 'undefined') {
      // TODO: Remove fb.me link
      if (typeof localRequestAnimationFrame !== 'function') {
        console.error(
          "This browser doesn't support requestAnimationFrame. " +
            'Make sure that you load a ' +
            'polyfill in older browsers. https://fb.me/react-polyfills',
        );
      }
      if (typeof localCancelAnimationFrame !== 'function') {
        console.error(
          "This browser doesn't support cancelAnimationFrame. " +
            'Make sure that you load a ' +
            'polyfill in older browsers. https://fb.me/react-polyfills',
        );
      }
    }
  
    var scheduledHostCallback = null;
    var isMessageEventScheduled = false;
    var timeoutTime = -1;
  
    var isAnimationFrameScheduled = false;
  
    var isFlushingHostCallback = false;
  
    var frameDeadline = 0;
    // We start out assuming that we run at 30fps but then the heuristic tracking
    // will adjust this value to a faster fps if we get more frequent animation
    // frames.
    var previousFrameTime = 33;
    var activeFrameTime = 33;
  
    getFrameDeadline = function() {
      return frameDeadline;
    };
  
    // We use the postMessage trick to defer idle work until after the repaint.
    var messageKey =
      '__reactIdleCallback$' +
      Math.random()
        .toString(36)
        .slice(2);
    var idleTick = function(event) {
      if (event.source !== window || event.data !== messageKey) {
        return;
      }
  
      isMessageEventScheduled = false;
  
      var prevScheduledCallback = scheduledHostCallback;
      var prevTimeoutTime = timeoutTime;
      scheduledHostCallback = null;
      timeoutTime = -1;
  
      var currentTime = getCurrentTime();
  
      var didTimeout = false;
      if (frameDeadline - currentTime <= 0) {
        //浏览器把一帧的时间已经用完了
        // There's no time left in this idle period. Check if the callback has
        // a timeout and whether it's been exceeded.
        if (prevTimeoutTime !== -1 && prevTimeoutTime <= currentTime) {
          //prevTimeoutTime <= currentTime 说明任务已经过期
          // Exceeded the timeout. Invoke the callback even though there's no
          // time left.
          //需要被强行执行
          didTimeout = true;
        } else {
          // No timeout.
          if (!isAnimationFrameScheduled) {
            // Schedule another animation callback so we retry later.
            isAnimationFrameScheduled = true;
            requestAnimationFrameWithTimeout(animationTick);
          }
          // Exit without invoking the callback.
          scheduledHostCallback = prevScheduledCallback;
          timeoutTime = prevTimeoutTime;
          return;
        }
      }
  
      if (prevScheduledCallback !== null) {
        isFlushingHostCallback = true;
  
        try {
          prevScheduledCallback(didTimeout);
        } finally {
          isFlushingHostCallback = false;
        }
      }
    };
    // Assumes that we have addEventListener in this environment. Might need
    // something better for old IE.
    window.addEventListener('message', idleTick, false);
  
    var animationTick = function(rafTime) {
      //rafTime 当前的倍调用的时间
      if (scheduledHostCallback !== null) {
        // Eagerly schedule the next animation callback at the beginning of the
        // frame. If the scheduler queue is not empty at the end of the frame, it
        // will continue flushing inside that callback. If the queue *is* empty,
        // then it will exit immediately. Posting the callback at the start of the
        // frame ensures it's fired within the earliest possible frame. If we
        // waited until the end of the frame to post the callback, we risk the
        // browser skipping a frame and not firing the callback until the frame
        // after that.
        //请求下一帧来做, 有很多的callback , 所以需要在下一帧中执行callback
        //animationTick 当前 animationTick 只执行一个 callback
        requestAnimationFrameWithTimeout(animationTick);
      } else { 
        // No pending work. Exit.
        isAnimationFrameScheduled = false;
        //没有方法需要调度
        return;
      }
  
      var nextFrameTime = rafTime - frameDeadline + activeFrameTime;//34
      // 一直到下一帧, 剩下可以执行的时间是多少
      // activeFrameTime是 33 
      // frameDeadline是 0
      // previousFrameTime是 33
      // rafTime 当前的被调用的时间
      // 
      if (
        nextFrameTime < activeFrameTime &&
        previousFrameTime < activeFrameTime
      ) {
        if (nextFrameTime < 8) {
          // Defensive coding. We don't support higher frame rates than 120hz.
          // If the calculated frame time gets lower than 8, it is probably a bug.
          nextFrameTime = 8;
        }
        if(nextFrameTime < previousFrameTime){
          activeFrameTime = previousFrameTime
        }else {
          activeFrameTime = nextFrameTime
        }
      } else {
        previousFrameTime = nextFrameTime;//34
      }
      frameDeadline = rafTime + activeFrameTime;//34
      if (!isMessageEventScheduled) {
        isMessageEventScheduled = true;
        //浏览器接收方 要等到浏览器刷新完成才进行
        window.postMessage(messageKey, '*');
      }
    };
  
    requestHostCallback = function(callback, absoluteTimeout) {
      scheduledHostCallback = callback;
      timeoutTime = absoluteTimeout;
      if (isFlushingHostCallback || absoluteTimeout < 0) {
        // isFlushingHostCallback 只在 channel.port1.onmessage 被设为 true
      // isFlushingHostCallback表示所添加的任务需要立即执行
      // 也就是说当正在执行任务或者新进来的任务已经过了过期时间
      // 马上执行新的任务，不再等到下一帧
        // Don't wait for the next frame. Continue working ASAP, in a new event.
        // 这种情况 不需要等待下一帧来做这件事情, 而是直接执行
        // absoluteTimeout < 0 表示已经超时
        //直接执行
        window.postMessage(messageKey, '*');
      } else if (!isAnimationFrameScheduled) {
        //isAnimationFrameScheduled 这个变量如果不是 true  证明还没有进度调度循环的过程
        // If rAF didn't already schedule one, we need to schedule a frame.
        // TODO: If this rAF doesn't materialize because the browser throttles, we
        // might want to still have setTimeout trigger rIC as a backup to ensure
        // that we keep performing work.
        isAnimationFrameScheduled = true;
        requestAnimationFrameWithTimeout(animationTick);
        //通过requestAnimationFrame会立马调用 animationTick 
        //这个callback执行完后, 立马进入浏览器的动画更新
        //给任务队列中插入一个任务 window.postMessage(messageKey, '*');
        //浏览器执行完后 调用这个队列
        //总共加起来是33ms
      }
    };
  
    cancelHostCallback = function() {
      //调度的内容 置空
      scheduledHostCallback = null;
      isMessageEventScheduled = false;
      timeoutTime = -1;
    };
  }
  
  export {
    ImmediatePriority as unstable_ImmediatePriority,
    UserBlockingPriority as unstable_UserBlockingPriority,
    NormalPriority as unstable_NormalPriority,
    IdlePriority as unstable_IdlePriority,
    unstable_runWithPriority,
    unstable_scheduleCallback,
    unstable_cancelCallback,
    unstable_wrapCallback,
    unstable_getCurrentPriorityLevel,
    getCurrentTime as unstable_now,
  };
  