Skip to content

Commit

Permalink
Rename unitOfWork -> workInProgress
Browse files Browse the repository at this point in the history
These values represent fibers that are incomplete. In the current
model they're mutated in place. In a completely immutable model
they would need to be cloned for every step they make progress.
I.e. one where the child is still in this WIP state and one when
it is complete.

To clarify this I'll name them workInProgress while they're in
that state, which is also what Jordan did in his prototype.
  • Loading branch information
sebmarkbage committed Jun 7, 2016
1 parent cce58ff commit 3a32d26
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 73 deletions.
90 changes: 45 additions & 45 deletions src/renderers/shared/fiber/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,114 +27,114 @@ var {
YieldComponent,
} = ReactTypesOfWork;

function updateFunctionalComponent(unitOfWork) {
var fn = unitOfWork.type;
var props = unitOfWork.input;
function updateFunctionalComponent(workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.input;
console.log('update fn:', fn.name);
var nextChildren = fn(props);

unitOfWork.child = ReactChildFiber.reconcileChildFibers(
unitOfWork,
unitOfWork.child,
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
workInProgress.child,
nextChildren
);
}

function updateHostComponent(unitOfWork) {
console.log('host component', unitOfWork.type, typeof unitOfWork.input.children === 'string' ? unitOfWork.input.children : '');
function updateHostComponent(workInProgress) {
console.log('host component', workInProgress.type, typeof workInProgress.input.children === 'string' ? workInProgress.input.children : '');

var nextChildren = unitOfWork.input.children;
unitOfWork.child = ReactChildFiber.reconcileChildFibers(
unitOfWork,
unitOfWork.child,
var nextChildren = workInProgress.input.children;
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
workInProgress.child,
nextChildren
);
}

function mountIndeterminateComponent(unitOfWork) {
var fn = unitOfWork.type;
var props = unitOfWork.input;
function mountIndeterminateComponent(workInProgress) {
var fn = workInProgress.type;
var props = workInProgress.input;
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
unitOfWork.tag = ClassComponent;
workInProgress.tag = ClassComponent;
} else {
console.log('performed work on fn:', fn.name);
// Proceed under the assumption that this is a functional component
unitOfWork.tag = FunctionalComponent;
workInProgress.tag = FunctionalComponent;
}
unitOfWork.child = ReactChildFiber.reconcileChildFibers(
unitOfWork,
unitOfWork.child,
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
workInProgress.child,
value
);
}

function updateCoroutineComponent(unitOfWork) {
var coroutine = (unitOfWork.input : ?ReactCoroutine);
function updateCoroutineComponent(workInProgress) {
var coroutine = (workInProgress.input : ?ReactCoroutine);
if (!coroutine) {
throw new Error('Should be resolved by now');
}
console.log('begin coroutine', unitOfWork.type.name);
unitOfWork.child = ReactChildFiber.reconcileChildFibers(
unitOfWork,
unitOfWork.child,
console.log('begin coroutine', workInProgress.type.name);
workInProgress.child = ReactChildFiber.reconcileChildFibers(
workInProgress,
workInProgress.child,
coroutine.children
);
}

function beginWork(unitOfWork : Fiber) : ?Fiber {
const alt = unitOfWork.alternate;
if (alt && unitOfWork.input === alt.memoizedInput) {
function beginWork(workInProgress : Fiber) : ?Fiber {
const alt = workInProgress.alternate;
if (alt && workInProgress.input === alt.memoizedInput) {
// The most likely scenario is that the previous copy of the tree contains
// the same input as the new one. In that case, we can just copy the output
// and children from that node.
unitOfWork.output = alt.output;
unitOfWork.child = alt.child;
workInProgress.output = alt.output;
workInProgress.child = alt.child;
return null;
}
if (unitOfWork.input === unitOfWork.memoizedInput) {
if (workInProgress.input === workInProgress.memoizedInput) {
// In a ping-pong scenario, this version could actually contain the
// old input. In that case, we can just bail out.
return null;
}
switch (unitOfWork.tag) {
switch (workInProgress.tag) {
case IndeterminateComponent:
mountIndeterminateComponent(unitOfWork);
mountIndeterminateComponent(workInProgress);
break;
case FunctionalComponent:
updateFunctionalComponent(unitOfWork);
updateFunctionalComponent(workInProgress);
break;
case ClassComponent:
console.log('class component', unitOfWork.input.type.name);
console.log('class component', workInProgress.input.type.name);
break;
case HostComponent:
updateHostComponent(unitOfWork);
updateHostComponent(workInProgress);
break;
case CoroutineHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
unitOfWork.tag = CoroutineComponent;
workInProgress.tag = CoroutineComponent;
// Intentionally fall through since this is now the same.
case CoroutineComponent:
updateCoroutineComponent(unitOfWork);
updateCoroutineComponent(workInProgress);
// This doesn't take arbitrary time so we could synchronously just begin
// eagerly do the work of unitOfWork.child as an optimization.
if (unitOfWork.child) {
return beginWork(unitOfWork.child);
// eagerly do the work of workInProgress.child as an optimization.
if (workInProgress.child) {
return beginWork(workInProgress.child);
}
break;
case YieldComponent:
// A yield component is just a placeholder, we can just run through the
// next one immediately.
if (unitOfWork.sibling) {
return beginWork(unitOfWork.sibling);
if (workInProgress.sibling) {
return beginWork(workInProgress.sibling);
}
return null;
default:
throw new Error('Unknown unit of work tag');
}
return unitOfWork.child;
return workInProgress.child;
}

exports.beginWork = beginWork;
38 changes: 19 additions & 19 deletions src/renderers/shared/fiber/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
}
}

function moveCoroutineToHandlerPhase(unitOfWork : Fiber) {
var coroutine = (unitOfWork.input : ?ReactCoroutine);
function moveCoroutineToHandlerPhase(workInProgress : Fiber) {
var coroutine = (workInProgress.input : ?ReactCoroutine);
if (!coroutine) {
throw new Error('Should be resolved by now');
}
Expand All @@ -67,12 +67,12 @@ function moveCoroutineToHandlerPhase(unitOfWork : 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.
unitOfWork.tag = CoroutineHandlerPhase;
workInProgress.tag = CoroutineHandlerPhase;

// Build up the yields.
// TODO: Compare this to a generator or opaque helpers like Children.
var yields : Array<ReifiedYield> = [];
var child = unitOfWork.child;
var child = workInProgress.child;
while (child) {
recursivelyFillYields(yields, child.output);
child = child.sibling;
Expand All @@ -81,34 +81,34 @@ function moveCoroutineToHandlerPhase(unitOfWork : Fiber) {
var props = coroutine.props;
var nextChildren = fn(props, yields);

unitOfWork.stateNode = ReactChildFiber.reconcileChildFibers(
unitOfWork,
unitOfWork.stateNode,
workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
workInProgress,
workInProgress.stateNode,
nextChildren
);
return unitOfWork.stateNode;
return workInProgress.stateNode;
}

exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
switch (unitOfWork.tag) {
exports.completeWork = function(workInProgress : Fiber) : ?Fiber {
switch (workInProgress.tag) {
case FunctionalComponent:
console.log('/functional component', unitOfWork.type.name);
transferOutput(unitOfWork.child, unitOfWork);
console.log('/functional component', workInProgress.type.name);
transferOutput(workInProgress.child, workInProgress);
break;
case ClassComponent:
console.log('/class component', unitOfWork.type.name);
transferOutput(unitOfWork.child, unitOfWork);
console.log('/class component', workInProgress.type.name);
transferOutput(workInProgress.child, workInProgress);
break;
case HostComponent:
console.log('/host component', unitOfWork.type);
console.log('/host component', workInProgress.type);
break;
case CoroutineComponent:
console.log('/coroutine component', unitOfWork.input.handler.name);
return moveCoroutineToHandlerPhase(unitOfWork);
console.log('/coroutine component', workInProgress.input.handler.name);
return moveCoroutineToHandlerPhase(workInProgress);
case CoroutineHandlerPhase:
transferOutput(unitOfWork.stateNode, unitOfWork);
transferOutput(workInProgress.stateNode, workInProgress);
// Reset the tag to now be a first phase coroutine.
unitOfWork.tag = CoroutineComponent;
workInProgress.tag = CoroutineComponent;
break;
case YieldComponent:
// Does nothing.
Expand Down
18 changes: 9 additions & 9 deletions src/renderers/shared/fiber/ReactFiberReconciler.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,38 +49,38 @@ module.exports = function<T, P, I>(config : HostConfig<T, P, I>) : Reconciler {

let nextUnitOfWork : ?Fiber = null;

function completeUnitOfWork(unitOfWork : Fiber) : ?Fiber {
function completeUnitOfWork(workInProgress : Fiber) : ?Fiber {
while (true) {
var next = completeWork(unitOfWork);
var next = completeWork(workInProgress);
if (next) {
// If completing this work spawned new work, do that next.
return next;
} else if (unitOfWork.sibling) {
} else if (workInProgress.sibling) {
// If there is more work to do in this parent, do that next.
return unitOfWork.sibling;
} else if (unitOfWork.parent) {
return workInProgress.sibling;
} else if (workInProgress.parent) {
// If there's no more work in this parent. Complete the parent.
// TODO: Stop using the parent for this purpose. I think this will break
// down in edge cases because when nodes are reused during bailouts, we
// don't know which of two parents was used. Instead we should maintain
// a temporary manual stack.
// $FlowFixMe: This downcast is not safe. It is intentionally an error.
unitOfWork = unitOfWork.parent;
workInProgress = workInProgress.parent;
} else {
// If we're at the root, there's no more work to do.
return null;
}
}
}

function performUnitOfWork(unitOfWork : Fiber) : ?Fiber {
var next = beginWork(unitOfWork);
function performUnitOfWork(workInProgress : Fiber) : ?Fiber {
var next = beginWork(workInProgress);
if (next) {
// If this spawns new work, do that next.
return next;
} else {
// Otherwise, complete the current work.
return completeUnitOfWork(unitOfWork);
return completeUnitOfWork(workInProgress);
}
}

Expand Down

0 comments on commit 3a32d26

Please sign in to comment.