packages/moon/src/executor/executor.js
function executeDiff(nodesOld, nodesNew, patches) {
	while (true) {
		const nodeOld = nodesOld.pop();
		const nodeOldNode = nodeOld.node;
		const nodeNew = nodesNew.pop();

		// If they have the same reference (hoisted) then skip diffing.
		if (nodeOldNode !== nodeNew) {
			if (nodeOldNode.name !== nodeNew.name) {
				// If they have different names, then replace the old node with the
				// new one.
				patches.push({
					type: patchTypes.replaceNode,
					nodeOld,
					nodeNew,
					nodeParent: null
				});
			} else if (nodeOldNode.type === types.text) {
				// If they both are text, then update the text content.
				if (nodeOldNode.data[""] !== nodeNew.data[""]) {
					patches.push({
						type: patchTypes.updateText,
						nodeOld,
						nodeNew,
						nodeParent: null
					});
				}
			} else {
				// If they both are normal elements, then update attributes, update
				// events, and diff the children for appends, deletes, or recursive
				// updates.
				patches.push({
					type: patchTypes.updateData,
					nodeOld,
					nodeNew,
					nodeParent: null
				});

				const childrenOld = nodeOld.children;
				const childrenNew = nodeNew.data.children;

				const childrenOldLength = childrenOld.length;
				const childrenNewLength = childrenNew.length;

				if (childrenOldLength === childrenNewLength) {
					// If the children have the same length then update both as
					// usual.
					for (let i = 0; i < childrenOldLength; i++) {
						nodesOld.push(childrenOld[i]);
						nodesNew.push(childrenNew[i]);
					}
				} else if (childrenOldLength > childrenNewLength) {
					// If there are more old children than new children, update the
					// corresponding ones and remove the extra old children.
					for (let i = 0; i < childrenNewLength; i++) {
						nodesOld.push(childrenOld[i]);
						nodesNew.push(childrenNew[i]);
					}

					for (let i = childrenNewLength; i < childrenOldLength; i++) {
						patches.push({
							type: patchTypes.removeNode,
							nodeOld: childrenOld[i],
							nodeNew: null,
							nodeParent: nodeOld
						});
					}
				} else {
					// If there are more new children than old children, update the
					// corresponding ones and append the extra new children.
					for (let i = 0; i < childrenOldLength; i++) {
						nodesOld.push(childrenOld[i]);
						nodesNew.push(childrenNew[i]);
					}

					for (let i = childrenOldLength; i < childrenNewLength; i++) {
						patches.push({
							type: patchTypes.appendNode,
							nodeOld: null,
							nodeNew: childrenNew[i],
							nodeParent: nodeOld
						});
					}
				}
			}
		}

		if (nodesOld.length === 0) {
			// Move to the patch phase if there is nothing left to do.
			executePatch(patches);

			break;
		} else if (performance.now() - executeStart >= 16) {
			// If the current frame doesn't have sufficient time left to keep
			// running then continue diffing in the next frame.
			requestAnimationFrame(() => {
				executeStart = performance.now();

				executeDiff(nodesOld, nodesNew, patches);
			});

			break;
		}
	}
}
function executeDiff(nodesOld, nodesNew, patches) {
	while (true) {
		const nodeOld = nodesOld.pop();
		const nodeOldNode = nodeOld.node;
		const nodeNew = nodesNew.pop();

		// If they have the same reference (hoisted) then skip diffing.
		if (nodeOldNode !== nodeNew) {
			if (nodeOldNode.name !== nodeNew.name) {
				// If they have different names, then replace the old node with the
				// new one.
				patches.push({
					type: patchTypes.replaceNode,
					nodeOld,
					nodeNew,
					nodeParent: null
				});
			} else if (nodeOldNode.type === types.text) {
				// If they both are text, then update the text content.
				if (nodeOldNode.data[""] !== nodeNew.data[""]) {
					patches.push({
						type: patchTypes.updateText,
						nodeOld,
						nodeNew,
						nodeParent: null
					});
				}
			} else {
				// If they both are normal elements, then update attributes, update
				// events, and diff the children for appends, deletes, or recursive
				// updates.
				patches.push({
					type: patchTypes.updateData,
					nodeOld,
					nodeNew,
					nodeParent: null
				});

				const childrenOld = nodeOld.children;
				const childrenNew = nodeNew.data.children;

				const childrenOldLength = childrenOld.length;
				const childrenNewLength = childrenNew.length;

				if (childrenOldLength === childrenNewLength) {
					// If the children have the same length then update both as
					// usual.
					for (let i = 0; i < childrenOldLength; i++) {
						nodesOld.push(childrenOld[i]);
						nodesNew.push(childrenNew[i]);
					}
				} else if (childrenOldLength > childrenNewLength) {
					// If there are more old children than new children, update the
					// corresponding ones and remove the extra old children.
					for (let i = 0; i < childrenNewLength; i++) {
						nodesOld.push(childrenOld[i]);
						nodesNew.push(childrenNew[i]);
					}

					for (let i = childrenNewLength; i < childrenOldLength; i++) {
						patches.push({
							type: patchTypes.removeNode,
							nodeOld: childrenOld[i],
							nodeNew: null,
							nodeParent: nodeOld
						});
					}
				} else {
					// If there are more new children than old children, update the
					// corresponding ones and append the extra new children.
					for (let i = 0; i < childrenOldLength; i++) {
						nodesOld.push(childrenOld[i]);
						nodesNew.push(childrenNew[i]);
					}

					for (let i = childrenOldLength; i < childrenNewLength; i++) {
						patches.push({
							type: patchTypes.appendNode,
							nodeOld: null,
							nodeNew: childrenNew[i],
							nodeParent: nodeOld
						});
					}
				}
			}
		}

		if (nodesOld.length === 0) {
			// Move to the patch phase if there is nothing left to do.
			executePatch(patches);

			break;
		} else if (performance.now() - executeStart >= 16) {
			// If the current frame doesn't have sufficient time left to keep
			// running then continue diffing in the next frame.
			requestAnimationFrame(() => {
				executeStart = performance.now();

				executeDiff(nodesOld, nodesNew, patches);
			});

			break;
		}
	}
}
function executeDiff ( nodesOld , nodesNew , patches ) { while ( true ) { const nodeOld = nodesOld . pop ( ) ; const nodeOldNode = nodeOld . node ; const nodeNew = nodesNew . pop ( ) ; // If they have the same reference (hoisted) then skip diffing. if ( nodeOldNode !== nodeNew ) { if ( nodeOldNode . name !== nodeNew . name ) { // If they have different names, then replace the old node with the // new one. patches . push ( { type : patchTypes . replaceNode , nodeOld , nodeNew , nodeParent : null } ) ; } else if ( nodeOldNode . type === types . text ) { // If they both are text, then update the text content. if ( nodeOldNode . data [ "" ] !== nodeNew . data [ "" ] ) { patches . push ( { type : patchTypes . updateText , nodeOld , nodeNew , nodeParent : null } ) ; } } else { // If they both are normal elements, then update attributes, update // events, and diff the children for appends, deletes, or recursive // updates. patches . push ( { type : patchTypes . updateData , nodeOld , nodeNew , nodeParent : null } ) ; const childrenOld = nodeOld . children ; const childrenNew = nodeNew . data . children ; const childrenOldLength = childrenOld . length ; const childrenNewLength = childrenNew . length ; if ( childrenOldLength === childrenNewLength ) { // If the children have the same length then update both as // usual. for ( let i = 0 ; i < childrenOldLength ; i ++ ) { nodesOld . push ( childrenOld [ i ] ) ; nodesNew . push ( childrenNew [ i ] ) ; } } else if ( childrenOldLength > childrenNewLength ) { // If there are more old children than new children, update the // corresponding ones and remove the extra old children. for ( let i = 0 ; i < childrenNewLength ; i ++ ) { nodesOld . push ( childrenOld [ i ] ) ; nodesNew . push ( childrenNew [ i ] ) ; } for ( let i = childrenNewLength ; i < childrenOldLength ; i ++ ) { patches . push ( { type : patchTypes . removeNode , nodeOld : childrenOld [ i ] , nodeNew : null , nodeParent : nodeOld } ) ; } } else { // If there are more new children than old children, update the // corresponding ones and append the extra new children. for ( let i = 0 ; i < childrenOldLength ; i ++ ) { nodesOld . push ( childrenOld [ i ] ) ; nodesNew . push ( childrenNew [ i ] ) ; } for ( let i = childrenOldLength ; i < childrenNewLength ; i ++ ) { patches . push ( { type : patchTypes . appendNode , nodeOld : null , nodeNew : childrenNew [ i ] , nodeParent : nodeOld } ) ; } } } } if ( nodesOld . length === 0 ) { // Move to the patch phase if there is nothing left to do. executePatch ( patches ) ; break ; } else if ( performance . now ( ) - executeStart >= 16 ) { // If the current frame doesn't have sufficient time left to keep // running then continue diffing in the next frame. requestAnimationFrame ( ( ) => { executeStart = performance . now ( ) ; executeDiff ( nodesOld , nodesNew , patches ) ; } ) ; break ; } } }
Finds changes between a new and old tree and creates a list of patches to
execute.

@param {Array} nodesOld
@param {Array} nodesNew
@param {Array} patches
Finds changes between a new and old tree and creates a list of patches to execute .