Frontend Development 10 min read

Iframe State Preservation and Vue Patch Mechanism Exploration

This article examines how iframe state can be preserved in a Vue‑based platform by using CSS display toggling, introduces an iframe resource pool with a competition eviction strategy, and analyzes Vue's patch algorithm and DOM insertBefore behavior to propose a solution that avoids unwanted iframe refreshes.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Iframe State Preservation and Vue Patch Mechanism Exploration

Iframe is a long‑standing HTML element that embeds another browsing context, offering cheap cross‑application page sharing, simple usage, high compatibility, and content isolation, and thus forms the first‑generation technology of front‑end platform architecture.

When multiple iframes are mounted in a parent page, preserving each window's state (input, scroll position, etc.) during switches is challenging; using CSS display:none with Vue's v-show prevents reloading by keeping inactive iframes in the DOM.

However, keeping many invisible iframes causes concurrent resource requests, degrading performance. To mitigate this, a fixed‑size iframe resource pool is introduced, employing a competition‑based eviction strategy that discards less‑recently activated windows when the pool is full, thereby limiting concurrent requests.

The article then investigates Vue's internal diff‑patch mechanism, presenting key source snippets:

Vue.prototype._update = function (vnode, hydrating) {
  if (!prevVnode) {
    // first render
    ...
  } else {
    // reactive update
    vm.$el = vm.__patch__(prevVnode, vnode)
  }
}

function patch(oldVnode, vnode, hydrating, removeOnly) {
  if (isUndef(oldVnode)) {
    // create new node
    ...
  } else {
    const isRealElement = isDef(oldVnode.nodeType)
    if (!isRealElement && sameVnode(oldVnode, vnode)) {
      patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly)
    } else {
      // initial render
      ...
    }
  }
  invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)
  return vnode.elm
}

function patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly) {
  if (isUndef(vnode.text)) {
    if (isDef(oldCh) && isDef(ch)) {
      if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
    } else {
      ...
    }
  }
}

function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
  let oldStartIdx = 0, newStartIdx = 0
  let oldEndIdx = oldCh.length - 1, newEndIdx = newCh.length - 1
  let oldStartVnode = oldCh[0], oldEndVnode = oldCh[oldEndIdx]
  let newStartVnode = newCh[0], newEndVnode = newCh[newEndIdx]
  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)) {
      // vnode moved right
      ...
    } else if (sameVnode(oldEndVnode, newStartVnode)) {
      // vnode moved left
      ...
    } else {
      // find new start vnode in old list
      if (sameVnode(vnodeToMove, newStartVnode)) {
        patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
        oldCh[idxInOld] = undefined
        canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
      } else {
        ...
      }
      newStartVnode = newCh[++newStartIdx]
    }
  }
}

These snippets illustrate how Vue decides between patching existing VNodes and inserting new DOM nodes; when nodeOps.insertBefore is invoked, the browser removes and re‑adds the iframe, causing a state refresh.

Experiments using MutationObserver in Chrome showed that any insertBefore operation on an iframe triggers removal and insertion, confirming the refresh behavior.

To avoid this, the eviction strategy of the iframe pool was altered from sorting to searching, ensuring that the relative order of old and new iframe VNodes remains unchanged, so Vue only performs a patch without invoking insertBefore , thereby preserving iframe state.

performancestate-managementPatchiframe
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.