vue2
响应式原理
graph LR
Object.defineProperty --> Object;
Object --> getter --收集依赖--> Dep;
Object --> setter --触发更新--> Dep;
Object.defineProperty --> Array;
Array --> 遍历元素;
Array --> 拦截变异方法;
Dep --> Watcher;
subgraph 依赖
Watcher --> 渲染Watcher --> 更新组件;
Watcher --> watch --异步--> 回调函数;
Watcher --> computed --同步--> getter函数;
end
更新原理
graph TD
A(patch) --> B{oldVnode?};
B --yes--> C1(createElm);
B --no--> C2(patchVnode);
graph LR
patchVnode -- oldCh--> removeVnodes;
patchVnode -- ch--> addVnodes;
patchVnode -- oldCh,ch--> updateChildren;
function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
let oldStartIdx = 0
let newStartIdx = 0
let oldEndIdx = oldCh.length - 1
let oldStartVnode = oldCh[0]
let oldEndVnode = oldCh[oldEndIdx]
let newEndIdx = newCh.length - 1
let newStartVnode = newCh[0]
let newEndVnode = newCh[newEndIdx]
let oldKeyToIdx, idxInOld, vnodeToMove, refElm
const canMove = !removeOnly
if (process.env.NODE_ENV !== 'production') {
checkDuplicateKeys(newCh)
}
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (isUndef(oldStartVnode)) {
oldStartVnode = oldCh[++oldStartIdx]
} else if (isUndef(oldEndVnode)) {
oldEndVnode = oldCh[--oldEndIdx]
} else if (sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
oldStartVnode = oldCh[++oldStartIdx]
newStartVnode = newCh[++newStartIdx]
} else if (sameVnode(oldEndVnode, newEndVnode)) {
patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
oldEndVnode = oldCh[--oldEndIdx]
newEndVnode = newCh[--newEndIdx]
} else if (sameVnode(oldStartVnode, newEndVnode)) {
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
oldStartVnode = oldCh[++oldStartIdx]
newEndVnode = newCh[--newEndIdx]
} else if (sameVnode(oldEndVnode, newStartVnode)) {
patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
oldEndVnode = oldCh[--oldEndIdx]
newStartVnode = newCh[++newStartIdx]
} else {
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
idxInOld = isDef(newStartVnode.key)
? oldKeyToIdx[newStartVnode.key]
: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
if (isUndef(idxInOld)) {
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
} else {
vnodeToMove = oldCh[idxInOld]
if (sameVnode(vnodeToMove, newStartVnode)) {
patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
oldCh[idxInOld] = undefined
canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
} else {
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
}
}
newStartVnode = newCh[++newStartIdx]
}
}
if (oldStartIdx > oldEndIdx) {
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
} else if (newStartIdx > newEndIdx) {
removeVnodes(oldCh, oldStartIdx, oldEndIdx)
}
}
vue3
响应式原理
graph LR
Object/Array --> Proxy;
Proxy--> set --add/set--> A1(trigger);
Proxy ---> get --key--> A2(track);
Proxy ---> deleteProperty --delete--> A1(trigger);
Proxy ---> ownKeys --ITERATE_KEY/length--> A2(track);
Proxy ---> has --key--> A2(track);
graph LR
Map/Set --Map--> get方法 --key--> A2(track);
Map/Set --Map--> set方法 --add/set--> A1(trigger);
Map/Set --Map,Set--> has方法 --key--> A2(track);
Map/Set --Set--> add方法 --add--> A1(trigger);
Map/Set --Map,Set--> delete方法 --delete--> A1(trigger);
Map/Set --Map,Set--> clear方法 --clear--> A1(trigger);
Map/Set --Map,Set--> forEach方法 --ITERATE_KEY--> A2(track);
Map/Set --Map,Set--> keys,values,entries,Symbol.iterator方法 --MAP_KEY_ITERATE_KEY/ITERATE_KEY--> A2(track);
graph LR
A2(track) --dep--> B2(activeEffect)
graph LR
A1(trigger) --> B1-1(clear) --> 所有依赖;
A1(trigger) --key--> B1-2(add);
A1(trigger) --key--> B1-3(delete);
A1(trigger) --key--> B1-4(set);
B1-2(add) --Object---> C1-1(ITERATE_KEY);
B1-2(add) --Array---> C1-2(length);
B1-2(add) --Map---> C1-3(MAP_KEY_ITERATE_KEY);
B1-3(delete) --Array---> C1-2(length);
B1-3(delete) --Map---> C1-3(MAP_KEY_ITERATE_KEY);
B1-4(set) --Map---> C1-3(MAP_KEY_ITERATE_KEY)
总体流程
graph LR
A1(createApp) --> B1(mount) --> C1(createVNode) --> D1(render);
graph LR
A1(render) --> B1(patch);
B1(patch) --文本--> C1(processText);
B1(patch) --注释--> C2(processCommentNode);
B1(patch) --片段--> C3(processFragment);
B1(patch) --元素--> C4(processElement);
B1(patch) --组件--> C5(processComponent);
B1(patch) --TELEPORT/SUSPENSE--> C6(Comp.process);
graph LR
A1(processComponent) --> B1(mountComponent);
A1(processComponent) --> B2(updateComponent);
B1(mountComponent) --> C1(createComponentInstance) --> D1(setupComponent) --> E1(setupRenderEffect) --> C2(update);
B2(updateComponent) --> C2(update);
C2(update) --> F1(patch);
graph LR
A1(setupComponent) --> B1(validateComponentName) --> C1(validateDirectiveName) --> D1(createSetupContext) --> E1(handleSetupResult) --> F1(finishComponentSetup) --> G1(compile) --> H1(applyOptions);
graph LR
A1(processElement) --> B1(mountElement);
A1(processElement) --> B2(patchElement);
B1(mountElement) --TEXT_CHILDREN--> C1(hostSetElementText);
B1(mountElement) --ARRAY_CHILDREN--> C2(mountChildren);
C2(mountChildren) --遍历--> D1(patch);
B2(patchElement) --> C3(patchBlockChildren) --遍历--> D1(patch);
B2(patchElement) --> C4(patchChildren);
C4(patchChildren) --KEYED_FRAGMENT--> C5(patchKeyedChildren);
C4(patchChildren) --UNKEYED_FRAGMENT--> C6(patchUnkeyedChildren) --遍历--> D1(patch);
graph LR
A1(processText) --> B1(hostCreateText) --> C1(hostInsert);
A1(processText) --> B2(hostSetText);