Dependency injection in the begin/complete/commit phases

This just makes them instantiable so that we can get access to the
host config in these.
This commit is contained in:
Sebastian Markbage
2016-06-29 17:24:18 -07:00
parent f84a8eabc7
commit a4b8bebe18
4 changed files with 341 additions and 311 deletions
+195 -188
View File
@@ -14,6 +14,7 @@
import type { ReactCoroutine } from 'ReactCoroutine';
import type { Fiber } from 'ReactFiber';
import type { HostConfig } from 'ReactFiberReconciler';
var ReactChildFiber = require('ReactChildFiber');
var ReactTypeOfWork = require('ReactTypeOfWork');
@@ -33,211 +34,217 @@ var {
} = require('ReactPriorityLevel');
var { findNextUnitOfWorkAtPriority } = require('ReactFiberPendingWork');
function reconcileChildren(current, workInProgress, nextChildren) {
const priority = workInProgress.pendingWorkPriority;
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
current ? current.child : null,
nextChildren,
priority
);
}
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
function updateFunctionalComponent(current, workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
console.log('update fn:', fn.name);
var nextChildren = fn(props);
reconcileChildren(current, workInProgress, nextChildren);
workInProgress.pendingWorkPriority = NoWork;
}
function updateHostComponent(current, workInProgress) {
console.log('host component', workInProgress.type, typeof workInProgress.pendingProps.children === 'string' ? workInProgress.pendingProps.children : '');
var nextChildren = workInProgress.pendingProps.children;
let priority = workInProgress.pendingWorkPriority;
if (workInProgress.pendingProps.hidden && priority !== OffscreenPriority) {
// If this host component is hidden, we can reconcile its children at
// the lowest priority and bail out from this particular pass. Unless, we're
// currently reconciling the lowest priority.
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
current ? current.child : null,
nextChildren,
OffscreenPriority
);
workInProgress.pendingWorkPriority = OffscreenPriority;
return null;
} else {
function reconcileChildren(current, workInProgress, nextChildren) {
const priority = workInProgress.pendingWorkPriority;
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
current ? current.child : null,
nextChildren,
priority
);
}
function updateFunctionalComponent(current, workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
console.log('update fn:', fn.name);
var nextChildren = fn(props);
reconcileChildren(current, workInProgress, nextChildren);
workInProgress.pendingWorkPriority = NoWork;
return workInProgress.child;
}
}
function mountIndeterminateComponent(current, workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
var value = fn(props);
if (typeof value === 'object' && value && typeof value.render === 'function') {
console.log('performed work on class:', fn.name);
// Proceed under the assumption that this is a class instance
workInProgress.tag = ClassComponent;
if (workInProgress.alternate) {
workInProgress.alternate.tag = ClassComponent;
}
} else {
console.log('performed work on fn:', fn.name);
// Proceed under the assumption that this is a functional component
workInProgress.tag = FunctionalComponent;
if (workInProgress.alternate) {
workInProgress.alternate.tag = FunctionalComponent;
function updateHostComponent(current, workInProgress) {
console.log('host component', workInProgress.type, typeof workInProgress.pendingProps.children === 'string' ? workInProgress.pendingProps.children : '');
var nextChildren = workInProgress.pendingProps.children;
let priority = workInProgress.pendingWorkPriority;
if (workInProgress.pendingProps.hidden && priority !== OffscreenPriority) {
// If this host component is hidden, we can reconcile its children at
// the lowest priority and bail out from this particular pass. Unless, we're
// currently reconciling the lowest priority.
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
current ? current.child : null,
nextChildren,
OffscreenPriority
);
workInProgress.pendingWorkPriority = OffscreenPriority;
return null;
} else {
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
current ? current.child : null,
nextChildren,
priority
);
workInProgress.pendingWorkPriority = NoWork;
return workInProgress.child;
}
}
reconcileChildren(current, workInProgress, value);
workInProgress.pendingWorkPriority = NoWork;
}
function updateCoroutineComponent(current, workInProgress) {
var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
if (!coroutine) {
throw new Error('Should be resolved by now');
}
console.log('begin coroutine', workInProgress.type.name);
reconcileChildren(current, workInProgress, coroutine.children);
workInProgress.pendingWorkPriority = NoWork;
}
function reuseChildren(returnFiber : Fiber, firstChild : Fiber) {
// TODO: None of this should be necessary if structured better.
// The returnFiber pointer only needs to be updated when we walk into this child
// which we don't do right now. If the pending work priority indicated only
// if a child has work rather than if the node has work, then we would know
// by a single lookup on workInProgress rather than having to go through
// each child.
let child = firstChild;
do {
// Update the returnFiber of the child to the newest fiber.
child.return = returnFiber;
// Retain the priority if there's any work left to do in the children.
if (child.pendingWorkPriority !== NoWork &&
(returnFiber.pendingWorkPriority === NoWork ||
returnFiber.pendingWorkPriority > child.pendingWorkPriority)) {
returnFiber.pendingWorkPriority = child.pendingWorkPriority;
}
} while (child = child.sibling);
}
function beginWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
if (current && workInProgress.pendingProps === current.memoizedProps) {
// The most likely scenario is that the previous copy of the tree contains
// the same props as the new one. In that case, we can just copy the output
// and children from that node.
workInProgress.memoizedProps = workInProgress.pendingProps;
workInProgress.output = current.output;
const priorityLevel = workInProgress.pendingWorkPriority;
workInProgress.pendingProps = null;
workInProgress.pendingWorkPriority = NoWork;
workInProgress.stateNode = current.stateNode;
if (current.child) {
// If we bail out but still has work with the current priority in this
// subtree, we need to go find it right now. If we don't, we won't flush
// it until the next tick.
workInProgress.child = current.child;
reuseChildren(workInProgress, workInProgress.child);
if (workInProgress.pendingWorkPriority <= priorityLevel) {
// TODO: This passes the current node and reads the priority level and
// pending props from that. We want it to read our priority level and
// pending props from the work in progress. Needs restructuring.
return findNextUnitOfWorkAtPriority(workInProgress.alternate, priorityLevel);
} else {
return null;
function mountIndeterminateComponent(current, workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
var value = fn(props);
if (typeof value === 'object' && value && typeof value.render === 'function') {
console.log('performed work on class:', fn.name);
// Proceed under the assumption that this is a class instance
workInProgress.tag = ClassComponent;
if (workInProgress.alternate) {
workInProgress.alternate.tag = ClassComponent;
}
} else {
workInProgress.child = null;
console.log('performed work on fn:', fn.name);
// Proceed under the assumption that this is a functional component
workInProgress.tag = FunctionalComponent;
if (workInProgress.alternate) {
workInProgress.alternate.tag = FunctionalComponent;
}
}
reconcileChildren(current, workInProgress, value);
workInProgress.pendingWorkPriority = NoWork;
}
function updateCoroutineComponent(current, workInProgress) {
var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
if (!coroutine) {
throw new Error('Should be resolved by now');
}
console.log('begin coroutine', workInProgress.type.name);
reconcileChildren(current, workInProgress, coroutine.children);
workInProgress.pendingWorkPriority = NoWork;
}
function reuseChildren(returnFiber : Fiber, firstChild : Fiber) {
// TODO: None of this should be necessary if structured better.
// The returnFiber pointer only needs to be updated when we walk into this child
// which we don't do right now. If the pending work priority indicated only
// if a child has work rather than if the node has work, then we would know
// by a single lookup on workInProgress rather than having to go through
// each child.
let child = firstChild;
do {
// Update the returnFiber of the child to the newest fiber.
child.return = returnFiber;
// Retain the priority if there's any work left to do in the children.
if (child.pendingWorkPriority !== NoWork &&
(returnFiber.pendingWorkPriority === NoWork ||
returnFiber.pendingWorkPriority > child.pendingWorkPriority)) {
returnFiber.pendingWorkPriority = child.pendingWorkPriority;
}
} while (child = child.sibling);
}
function beginWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
if (current && workInProgress.pendingProps === current.memoizedProps) {
// The most likely scenario is that the previous copy of the tree contains
// the same props as the new one. In that case, we can just copy the output
// and children from that node.
workInProgress.memoizedProps = workInProgress.pendingProps;
workInProgress.output = current.output;
const priorityLevel = workInProgress.pendingWorkPriority;
workInProgress.pendingProps = null;
workInProgress.pendingWorkPriority = NoWork;
workInProgress.stateNode = current.stateNode;
if (current.child) {
// If we bail out but still has work with the current priority in this
// subtree, we need to go find it right now. If we don't, we won't flush
// it until the next tick.
workInProgress.child = current.child;
reuseChildren(workInProgress, workInProgress.child);
if (workInProgress.pendingWorkPriority <= priorityLevel) {
// TODO: This passes the current node and reads the priority level and
// pending props from that. We want it to read our priority level and
// pending props from the work in progress. Needs restructuring.
return findNextUnitOfWorkAtPriority(workInProgress.alternate, priorityLevel);
} else {
return null;
}
} else {
workInProgress.child = null;
return null;
}
}
if (!workInProgress.hasWorkInProgress &&
workInProgress.pendingProps === workInProgress.memoizedProps &&
workInProgress.pendingWorkPriority === NoWork) {
// If we started this work before, and finished it, or if we're in a
// ping-pong update scenario, this version could already be what we're
// looking for. In that case, we should be able to just bail out.
workInProgress.pendingProps = null;
// TODO: We should be able to bail out if there is remaining work at a lower
// priority too. However, I don't know if that is safe or even better since
// the other tree could've potentially finished that work.
return null;
}
workInProgress.hasWorkInProgress = true;
switch (workInProgress.tag) {
case IndeterminateComponent:
mountIndeterminateComponent(current, workInProgress);
return workInProgress.child;
case FunctionalComponent:
updateFunctionalComponent(current, workInProgress);
return workInProgress.child;
case ClassComponent:
console.log('class component', workInProgress.pendingProps.type.name);
return workInProgress.child;
case HostContainer:
reconcileChildren(current, workInProgress, workInProgress.pendingProps);
// A yield component is just a placeholder, we can just run through the
// next one immediately.
workInProgress.pendingWorkPriority = NoWork;
if (workInProgress.child) {
return beginWork(
workInProgress.child.alternate,
workInProgress.child
);
}
return null;
case HostComponent:
return updateHostComponent(current, workInProgress);
case CoroutineHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
workInProgress.tag = CoroutineComponent;
// Intentionally fall through since this is now the same.
case CoroutineComponent:
updateCoroutineComponent(current, workInProgress);
// This doesn't take arbitrary time so we could synchronously just begin
// eagerly do the work of workInProgress.child as an optimization.
if (workInProgress.child) {
return beginWork(
workInProgress.child.alternate,
workInProgress.child
);
}
return workInProgress.child;
case YieldComponent:
// A yield component is just a placeholder, we can just run through the
// next one immediately.
workInProgress.pendingWorkPriority = NoWork;
if (workInProgress.sibling) {
return beginWork(
workInProgress.sibling.alternate,
workInProgress.sibling
);
}
return null;
default:
throw new Error('Unknown unit of work tag');
}
}
if (!workInProgress.hasWorkInProgress &&
workInProgress.pendingProps === workInProgress.memoizedProps &&
workInProgress.pendingWorkPriority === NoWork) {
// If we started this work before, and finished it, or if we're in a
// ping-pong update scenario, this version could already be what we're
// looking for. In that case, we should be able to just bail out.
workInProgress.pendingProps = null;
// TODO: We should be able to bail out if there is remaining work at a lower
// priority too. However, I don't know if that is safe or even better since
// the other tree could've potentially finished that work.
return null;
}
return {
beginWork,
};
workInProgress.hasWorkInProgress = true;
switch (workInProgress.tag) {
case IndeterminateComponent:
mountIndeterminateComponent(current, workInProgress);
return workInProgress.child;
case FunctionalComponent:
updateFunctionalComponent(current, workInProgress);
return workInProgress.child;
case ClassComponent:
console.log('class component', workInProgress.pendingProps.type.name);
return workInProgress.child;
case HostContainer:
reconcileChildren(current, workInProgress, workInProgress.pendingProps);
// A yield component is just a placeholder, we can just run through the
// next one immediately.
workInProgress.pendingWorkPriority = NoWork;
if (workInProgress.child) {
return beginWork(
workInProgress.child.alternate,
workInProgress.child
);
}
return null;
case HostComponent:
return updateHostComponent(current, workInProgress);
case CoroutineHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
workInProgress.tag = CoroutineComponent;
// Intentionally fall through since this is now the same.
case CoroutineComponent:
updateCoroutineComponent(current, workInProgress);
// This doesn't take arbitrary time so we could synchronously just begin
// eagerly do the work of workInProgress.child as an optimization.
if (workInProgress.child) {
return beginWork(
workInProgress.child.alternate,
workInProgress.child
);
}
return workInProgress.child;
case YieldComponent:
// A yield component is just a placeholder, we can just run through the
// next one immediately.
workInProgress.pendingWorkPriority = NoWork;
if (workInProgress.sibling) {
return beginWork(
workInProgress.sibling.alternate,
workInProgress.sibling
);
}
return null;
default:
throw new Error('Unknown unit of work tag');
}
}
exports.beginWork = beginWork;
};
@@ -13,6 +13,7 @@
'use strict';
import type { Fiber } from 'ReactFiber';
import type { HostConfig } from 'ReactFiberReconciler';
var ReactTypeOfWork = require('ReactTypeOfWork');
var {
@@ -21,18 +22,26 @@ var {
HostComponent,
} = ReactTypeOfWork;
exports.commitWork = function(finishedWork : Fiber) : void {
switch (finishedWork.tag) {
case ClassComponent:
// TODO: Fire componentDidMount/componentDidUpdate, update refs
return;
case HostContainer:
// TODO: Attach children to root container.
return;
case HostComponent:
console.log('commit updates to host component', finishedWork.type);
return;
default:
throw new Error('This unit of work tag should not have side-effects.');
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
function commitWork(finishedWork : Fiber) : void {
switch (finishedWork.tag) {
case ClassComponent:
// TODO: Fire componentDidMount/componentDidUpdate, update refs
return;
case HostContainer:
// TODO: Attach children to root container.
return;
case HostComponent:
console.log('commit updates to host component', finishedWork.type);
return;
default:
throw new Error('This unit of work tag should not have side-effects.');
}
}
return {
commitWork,
};
};
@@ -14,6 +14,7 @@
import type { ReactCoroutine } from 'ReactCoroutine';
import type { Fiber } from 'ReactFiber';
import type { HostConfig } from 'ReactFiberReconciler';
import type { ReifiedYield } from 'ReactReifiedYield';
@@ -30,117 +31,125 @@ var {
YieldComponent,
} = ReactTypeOfWork;
function markForPostEffect(workInProgress : Fiber) {
// Schedule a side-effect on this fiber, after the children's side-effects.
if (workInProgress.lastEffect) {
workInProgress.lastEffect.nextEffect = workInProgress;
} else {
workInProgress.firstEffect = workInProgress;
}
workInProgress.lastEffect = workInProgress;
}
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
function transferOutput(child : ?Fiber, returnFiber : Fiber) {
// If we have a single result, we just pass that through as the output to
// avoid unnecessary traversal. When we have multiple output, we just pass
// the linked list of fibers that has the individual output values.
returnFiber.output = (child && !child.sibling) ? child.output : child;
returnFiber.memoizedProps = returnFiber.pendingProps;
}
function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
if (!output) {
// Ignore nulls etc.
} else if (output.tag !== undefined) { // TODO: Fix this fragile duck test.
// Detect if this is a fiber, if so it is a fragment result.
// $FlowFixMe: Refinement issue.
var item = (output : Fiber);
do {
recursivelyFillYields(yields, item.output);
item = item.sibling;
} while (item);
} else {
// $FlowFixMe: Refinement issue. If it is not a Fiber or null, it is a yield
yields.push(output);
}
}
function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) {
var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
if (!coroutine) {
throw new Error('Should be resolved by now');
function markForPostEffect(workInProgress : Fiber) {
// Schedule a side-effect on this fiber, after the children's side-effects.
if (workInProgress.lastEffect) {
workInProgress.lastEffect.nextEffect = workInProgress;
} else {
workInProgress.firstEffect = workInProgress;
}
workInProgress.lastEffect = workInProgress;
}
// First step of the coroutine has completed. Now we need to do the second.
// TODO: It would be nice to have a multi stage coroutine represented by a
// single component, or at least tail call optimize nested ones. Currently
// that requires additional fields that we don't want to add to the fiber.
// So this requires nested handlers.
// Note: This doesn't mutate the alternate node. I don't think it needs to
// since this stage is reset for every pass.
workInProgress.tag = CoroutineHandlerPhase;
// Build up the yields.
// TODO: Compare this to a generator or opaque helpers like Children.
var yields : Array<ReifiedYield> = [];
var child = workInProgress.child;
while (child) {
recursivelyFillYields(yields, child.output);
child = child.sibling;
function transferOutput(child : ?Fiber, returnFiber : Fiber) {
// If we have a single result, we just pass that through as the output to
// avoid unnecessary traversal. When we have multiple output, we just pass
// the linked list of fibers that has the individual output values.
returnFiber.output = (child && !child.sibling) ? child.output : child;
returnFiber.memoizedProps = returnFiber.pendingProps;
}
var fn = coroutine.handler;
var props = coroutine.props;
var nextChildren = fn(props, yields);
var currentFirstChild = current ? current.stateNode : null;
// Inherit the priority of the returnFiber.
const priority = workInProgress.pendingWorkPriority;
workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
workInProgress,
currentFirstChild,
nextChildren,
priority
);
return workInProgress.stateNode;
}
exports.completeWork = function(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
switch (workInProgress.tag) {
case FunctionalComponent:
console.log('/functional component', workInProgress.type.name);
transferOutput(workInProgress.child, workInProgress);
return null;
case ClassComponent:
console.log('/class component', workInProgress.type.name);
transferOutput(workInProgress.child, workInProgress);
return null;
case HostContainer:
return null;
case HostComponent:
transferOutput(workInProgress.child, workInProgress);
if (workInProgress.alternate) {
// If we have an alternate, that means this is an update and we need to
// schedule a side-effect to do the updates.
markForPostEffect(workInProgress);
}
console.log('/host component', workInProgress.type);
return null;
case CoroutineComponent:
console.log('/coroutine component', workInProgress.pendingProps.handler.name);
return moveCoroutineToHandlerPhase(current, workInProgress);
case CoroutineHandlerPhase:
transferOutput(workInProgress.stateNode, workInProgress);
// Reset the tag to now be a first phase coroutine.
workInProgress.tag = CoroutineComponent;
return null;
case YieldComponent:
// Does nothing.
return null;
// Error cases
case IndeterminateComponent:
throw new Error('An indeterminate component should have become determinate before completing.');
default:
throw new Error('Unknown unit of work tag');
function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
if (!output) {
// Ignore nulls etc.
} else if (output.tag !== undefined) { // TODO: Fix this fragile duck test.
// Detect if this is a fiber, if so it is a fragment result.
// $FlowFixMe: Refinement issue.
var item = (output : Fiber);
do {
recursivelyFillYields(yields, item.output);
item = item.sibling;
} while (item);
} else {
// $FlowFixMe: Refinement issue. If it is not a Fiber or null, it is a yield
yields.push(output);
}
}
function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) {
var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
if (!coroutine) {
throw new Error('Should be resolved by now');
}
// First step of the coroutine has completed. Now we need to do the second.
// TODO: It would be nice to have a multi stage coroutine represented by a
// single component, or at least tail call optimize nested ones. Currently
// that requires additional fields that we don't want to add to the fiber.
// So this requires nested handlers.
// Note: This doesn't mutate the alternate node. I don't think it needs to
// since this stage is reset for every pass.
workInProgress.tag = CoroutineHandlerPhase;
// Build up the yields.
// TODO: Compare this to a generator or opaque helpers like Children.
var yields : Array<ReifiedYield> = [];
var child = workInProgress.child;
while (child) {
recursivelyFillYields(yields, child.output);
child = child.sibling;
}
var fn = coroutine.handler;
var props = coroutine.props;
var nextChildren = fn(props, yields);
var currentFirstChild = current ? current.stateNode : null;
// Inherit the priority of the returnFiber.
const priority = workInProgress.pendingWorkPriority;
workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
workInProgress,
currentFirstChild,
nextChildren,
priority
);
return workInProgress.stateNode;
}
function completeWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
switch (workInProgress.tag) {
case FunctionalComponent:
console.log('/functional component', workInProgress.type.name);
transferOutput(workInProgress.child, workInProgress);
return null;
case ClassComponent:
console.log('/class component', workInProgress.type.name);
transferOutput(workInProgress.child, workInProgress);
return null;
case HostContainer:
return null;
case HostComponent:
transferOutput(workInProgress.child, workInProgress);
if (workInProgress.alternate) {
// If we have an alternate, that means this is an update and we need to
// schedule a side-effect to do the updates.
markForPostEffect(workInProgress);
}
console.log('/host component', workInProgress.type);
return null;
case CoroutineComponent:
console.log('/coroutine component', workInProgress.pendingProps.handler.name);
return moveCoroutineToHandlerPhase(current, workInProgress);
case CoroutineHandlerPhase:
transferOutput(workInProgress.stateNode, workInProgress);
// Reset the tag to now be a first phase coroutine.
workInProgress.tag = CoroutineComponent;
return null;
case YieldComponent:
// Does nothing.
return null;
// Error cases
case IndeterminateComponent:
throw new Error('An indeterminate component should have become determinate before completing.');
default:
throw new Error('Unknown unit of work tag');
}
}
return {
completeWork,
};
};
@@ -16,10 +16,11 @@ import type { Fiber } from 'ReactFiber';
import type { FiberRoot } from 'ReactFiberRoot';
import type { HostConfig } from 'ReactFiberReconciler';
var ReactFiberBeginWork = require('ReactFiberBeginWork');
var ReactFiberCompleteWork = require('ReactFiberCompleteWork');
var ReactFiberCommitWork = require('ReactFiberCommitWork');
var { cloneFiber } = require('ReactFiber');
var { beginWork } = require('ReactFiberBeginWork');
var { completeWork } = require('ReactFiberCompleteWork');
var { commitWork } = require('ReactFiberCommitWork');
var { findNextUnitOfWorkAtPriority } = require('ReactFiberPendingWork');
var {
@@ -33,6 +34,10 @@ var timeHeuristicForUnitOfWork = 1;
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
const { beginWork } = ReactFiberBeginWork(config);
const { completeWork } = ReactFiberCompleteWork(config);
const { commitWork } = ReactFiberCommitWork(config);
// const scheduleHighPriCallback = config.scheduleHighPriCallback;
const scheduleLowPriCallback = config.scheduleLowPriCallback;