成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React源碼閱讀:虛擬DOM的初始化

JerryZou / 2704人閱讀

摘要:虛擬的初始化在閱讀源碼前,我們先提出一個(gè)問(wèn)題,是如何將虛擬轉(zhuǎn)換為真實(shí)的呢有問(wèn)題以后我們才會(huì)更有目標(biāo)的閱讀代碼,下面我們就帶著這個(gè)問(wèn)題去思考。對(duì)類型的處理主要是更新屬性,然后通過(guò)創(chuàng)建節(jié)點(diǎn),并添加進(jìn)父節(jié)點(diǎn)。最后所有的虛擬都將轉(zhuǎn)為真實(shí)。

前言

本文的主要目的是閱讀源碼的過(guò)程中做下筆記和分享給有需要的小伙伴,可能會(huì)有紕漏和錯(cuò)誤,請(qǐng)讀者自行判斷,頭一次寫閱讀代碼的文章,可能寫得有點(diǎn)亂,有什么問(wèn)題歡迎一起探討一起進(jìn)步。

React的版本為16.4,主分支的代碼,只貼出部分關(guān)鍵代碼,完整代碼請(qǐng)到Github查看。

虛擬DOM的初始化 React.createElement

在閱讀源碼前,我們先提出一個(gè)問(wèn)題,React是如何將虛擬DOM轉(zhuǎn)換為真實(shí)的DOM呢?有問(wèn)題以后我們才會(huì)更有目標(biāo)的閱讀代碼,下面我們就帶著這個(gè)問(wèn)題去思考。

在平時(shí)工作中我們常常用JSX語(yǔ)法來(lái)創(chuàng)建React元素實(shí)例,但他們最后都會(huì)通過(guò)打包工具編譯成原生的JS代碼,通過(guò)React.createElement來(lái)創(chuàng)建。例如:

//  class ReactComponent extends React.Component {
//      render() {
//          return 

Hello React

; // } // } // 以上代碼會(huì)編譯為: class ReactComponent extends React.Component { render() { React.createElement( "p", { className: "class"}, "Hello React" ) } } // React.createElement(ReactComponent, { someProp: "prop" }, null);

這樣我們就可以創(chuàng)建得到React元素實(shí)例。
先來(lái)看看createElement的主要源碼(部分代碼省略):

function createElement(type, config, children) {
  let propName;

  const props = {};

  let key = null;
  let ref = null;
  let self = null;
  let source = null;

  if (config != null) {
    if (hasValidRef(config)) {
      //  如果有ref,將他取出來(lái)
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      //  如果有key,將他取出來(lái)
      key = "" + config.key;
    }

    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        //  將除ref,key等這些特殊的屬性放到新的props對(duì)象里
        props[propName] = config[propName];
      }
    }
  }

  //  獲取子元素
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  //  添加默認(rèn)props
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}
const ReactElement = function(type, key, ref, self, source, owner, props) {
  //  最終得到的React元素
  const element = {
    // This tag allows us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    _owner: owner,
  };

  return element;
};

是不是很簡(jiǎn)單呢,主要是把我們傳進(jìn)去的東西組成一個(gè)React元素對(duì)象,而type就是我們傳進(jìn)去的組件類型,他可以是一個(gè)類、函數(shù)或字符串(如"div")。

ReactDom.render

雖然我們已經(jīng)得到創(chuàng)建好的React元素,但React有是如何把React元素轉(zhuǎn)換為我們最終想要的DOM呢?就是通過(guò)ReactDom.render函數(shù)啦。

ReactDom.render(
  React.createElement(App),  
  document.getElementById("root")
 );

ReactDom.render的定義:

render(
    element: React$Element,
    container: DOMContainer,
    callback: ?Function,
  ) {
    return legacyRenderSubtreeIntoContainer(
      null,  /* 父組件 */
      element,  /* React元素 */
      container,  /* DOM容器 */
      false,
      callback,
    );
  }

legacyRenderSubtreeIntoContainer先獲取到React根容器對(duì)象(只貼部分代碼):

...
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
  container,
  forceHydrate,
);
...

因代碼過(guò)多只貼出通過(guò)legacyCreateRootFromDOMContainer最終得到的React根容器對(duì)象:

const NoWork = 0;

{
    _internalRoot: {
      current: uninitializedFiber,  // null
      containerInfo: containerInfo,  //  DOM容器
      pendingChildren: null,

      earliestPendingTime: NoWork,
      latestPendingTime: NoWork,
      earliestSuspendedTime: NoWork,
      latestSuspendedTime: NoWork,
      latestPingedTime: NoWork,

      didError: false,

      pendingCommitExpirationTime: NoWork,
      finishedWork: null,
      context: null,
      pendingContext: null,
      hydrate,
      nextExpirationTimeToWorkOn: NoWork,
      expirationTime: NoWork,
      firstBatch: null,
      nextScheduledRoot: null,
    },
    render: (children: ReactNodeList, callback: ?() => mixed) => Work,
    legacy_renderSubtreeIntoContainer: (
      parentComponent: ?React$Component,
      children: ReactNodeList,
      callback: ?() => mixed
    ) => Work,
    createBatch: () => Batch
}

在初始化React根容器對(duì)象root后,調(diào)用root.render開(kāi)始虛擬DOM的渲染過(guò)程。

DOMRenderer.unbatchedUpdates(() => {
  if (parentComponent != null) {
    root.legacy_renderSubtreeIntoContainer(
      parentComponent,
      children,
      callback,
    );
  } else {
    root.render(children, callback);
  }
});

因代碼量過(guò)大,就不逐一貼出詳細(xì)代碼,只貼出主要的函數(shù)的調(diào)用過(guò)程。

root.render(children, callback) -> 
DOMRenderer.updateContainer(children, root, null, work._onCommit) -> 
updateContainerAtExpirationTime(
    element,
    container,
    parentComponent,
    expirationTime,
    callback,
) ->
scheduleRootUpdate(current, element, expirationTime, callback) ->
scheduleWork(current, expirationTime) ->
requestWork(root, rootExpirationTime) ->
performWorkOnRoot(root, Sync, false) ->
renderRoot(root, false) -> 
workLoop(isYieldy) ->
performUnitOfWork(nextUnitOfWork: Fiber) => Fiber | null ->
beginWork(current, workInProgress, nextRenderExpirationTime)
Fiber

Fiber類型:

type Fiber = {|
  tag: TypeOfWork,
  key: null | string,

  // The function/class/module associated with this fiber.
  type: any,
  return: Fiber | null,

  // Singly Linked List Tree Structure.
  child: Fiber | null,
  sibling: Fiber | null,
  index: number,
  ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,

  memoizedProps: any, // The props used to create the output.
  updateQueue: UpdateQueue | null,
  memoizedState: any,
  
  mode: TypeOfMode,

  effectTag: TypeOfSideEffect,
  nextEffect: Fiber | null,
  firstEffect: Fiber | null,
  lastEffect: Fiber | null,
  
  expirationTime: ExpirationTime,

  alternate: Fiber | null,

  actualDuration?: number,
  actualStartTime?: number,
  selfBaseTime?: number,
  treeBaseTime?: number,

  _debugID?: number,
  _debugSource?: Source | null,
  _debugOwner?: Fiber | null,
  _debugIsCurrentlyTiming?: boolean,
|};
beginWork

按以上函數(shù)調(diào)用過(guò)程,我們來(lái)到beginWork函數(shù),它的作用主要是根據(jù)Fiber對(duì)象的tag來(lái)對(duì)組件進(jìn)行mount或update:

function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
): Fiber | null {
  if (enableProfilerTimer) {
    if (workInProgress.mode & ProfileMode) {
      markActualRenderTimeStarted(workInProgress);
    }
  }

  if (
    workInProgress.expirationTime === NoWork ||
    workInProgress.expirationTime > renderExpirationTime
  ) {
    return bailoutOnLowPriority(current, workInProgress);
  }

  //  根據(jù)組件類型來(lái)進(jìn)行不同處理
  switch (workInProgress.tag) {
    case IndeterminateComponent:
      //  不確定的組件類型
      return mountIndeterminateComponent(
        current,
        workInProgress,
        renderExpirationTime,
      );
    case FunctionalComponent:
      //  函數(shù)類型的組件
      return updateFunctionalComponent(current, workInProgress);
    case ClassComponent:
      //  類類型的組件,我們這次主要看這個(gè)
      return updateClassComponent(
        current,
        workInProgress,
        renderExpirationTime,
      );
    case HostRoot:
      return updateHostRoot(current, workInProgress, renderExpirationTime);
    case HostComponent:
      return updateHostComponent(current, workInProgress, renderExpirationTime);
    case HostText:
      return updateHostText(current, workInProgress);
    case TimeoutComponent:
      return updateTimeoutComponent(
        current,
        workInProgress,
        renderExpirationTime,
      );
    case HostPortal:
      return updatePortalComponent(
        current,
        workInProgress,
        renderExpirationTime,
      );
    case ForwardRef:
      return updateForwardRef(current, workInProgress);
    case Fragment:
      return updateFragment(current, workInProgress);
    case Mode:
      return updateMode(current, workInProgress);
    case Profiler:
      return updateProfiler(current, workInProgress);
    case ContextProvider:
      return updateContextProvider(
        current,
        workInProgress,
        renderExpirationTime,
      );
    case ContextConsumer:
      return updateContextConsumer(
        current,
        workInProgress,
        renderExpirationTime,
      );
    default:
      invariant(
        false,
        "Unknown unit of work tag. This error is likely caused by a bug in " +
          "React. Please file an issue.",
      );
  }
}
updateClassComponent

updateClassComponent的作用是對(duì)未初始化的類組件進(jìn)行初始化,對(duì)已經(jīng)初始化的組件更新重用

function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
) {
  const hasContext = pushLegacyContextProvider(workInProgress);
  let shouldUpdate;
  if (current === null) {
    if (workInProgress.stateNode === null) {
      //  如果還沒(méi)創(chuàng)建實(shí)例,初始化
      constructClassInstance(
        workInProgress,
        workInProgress.pendingProps,
        renderExpirationTime,
      );
      mountClassInstance(workInProgress, renderExpirationTime);

      shouldUpdate = true;
    } else {
      //  如果已經(jīng)創(chuàng)建實(shí)例,則重用實(shí)例
      shouldUpdate = resumeMountClassInstance(
        workInProgress,
        renderExpirationTime,
      );
    }
  } else {
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      renderExpirationTime,
    );
  }
  return finishClassComponent(
    current,
    workInProgress,
    shouldUpdate,
    hasContext,
    renderExpirationTime,
  );
}
constructClassInstance

實(shí)例化類組件:

function constructClassInstance(
  workInProgress: Fiber,
  props: any,
  renderExpirationTime: ExpirationTime,
): any {
  const ctor = workInProgress.type;  //  我們傳進(jìn)去的那個(gè)類
  const unmaskedContext = getUnmaskedContext(workInProgress);
  const needsContext = isContextConsumer(workInProgress);
  const context = needsContext
    ? getMaskedContext(workInProgress, unmaskedContext)
    : emptyContextObject;

  const instance = new ctor(props, context);  //  創(chuàng)建實(shí)例
  const state = (workInProgress.memoizedState =
    instance.state !== null && instance.state !== undefined
      ? instance.state
      : null);
  adoptClassInstance(workInProgress, instance);

  if (needsContext) {
    cacheContext(workInProgress, unmaskedContext, context);
  }

  return instance;
}
adoptClassInstance
function adoptClassInstance(workInProgress: Fiber, instance: any): void {
  instance.updater = classComponentUpdater;
  workInProgress.stateNode = instance;  //  將實(shí)例賦值給stateNode屬性
}
mountClassInstance

下面的代碼就有我們熟悉的componentWillMount生命周期出現(xiàn)啦,不過(guò)新版React已經(jīng)不建議使用它。

function mountClassInstance(
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
): void {
  const ctor = workInProgress.type;

  const instance = workInProgress.stateNode;
  const props = workInProgress.pendingProps;
  const unmaskedContext = getUnmaskedContext(workInProgress);

  instance.props = props;
  instance.state = workInProgress.memoizedState;
  instance.refs = emptyRefsObject;
  instance.context = getMaskedContext(workInProgress, unmaskedContext);

  let updateQueue = workInProgress.updateQueue;
  if (updateQueue !== null) {
    processUpdateQueue(
      workInProgress,
      updateQueue,
      props,
      instance,
      renderExpirationTime,
    );
    instance.state = workInProgress.memoizedState;
  }

  const getDerivedStateFromProps = workInProgress.type.getDerivedStateFromProps;
  if (typeof getDerivedStateFromProps === "function") {
    //  React新的生命周期函數(shù)
    applyDerivedStateFromProps(workInProgress, getDerivedStateFromProps, props);
    instance.state = workInProgress.memoizedState;
  }

  if (
    typeof ctor.getDerivedStateFromProps !== "function" &&
    typeof instance.getSnapshotBeforeUpdate !== "function" &&
    (typeof instance.UNSAFE_componentWillMount === "function" ||
      typeof instance.componentWillMount === "function")
  ) {
    //  如果沒(méi)有使用getDerivedStateFromProps而使用componentWillMount,兼容舊版
    callComponentWillMount(workInProgress, instance);
    updateQueue = workInProgress.updateQueue;
    if (updateQueue !== null) {
      processUpdateQueue(
        workInProgress,
        updateQueue,
        props,
        instance,
        renderExpirationTime,
      );
      instance.state = workInProgress.memoizedState;
    }
  }

  if (typeof instance.componentDidMount === "function") {
    workInProgress.effectTag |= Update;
  }
}
finishClassComponent

調(diào)用組件實(shí)例的render函數(shù)獲取需渲染的子元素,并把子元素進(jìn)行處理為Fiber類型,處理state和props:

function finishClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  shouldUpdate: boolean,
  hasContext: boolean,
  renderExpirationTime: ExpirationTime,
) {
  markRef(current, workInProgress);

  const didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect;

  if (!shouldUpdate && !didCaptureError) {
    if (hasContext) {
      invalidateContextProvider(workInProgress, false);
    }

    return bailoutOnAlreadyFinishedWork(current, workInProgress);
  }

  const ctor = workInProgress.type;
  const instance = workInProgress.stateNode;

  ReactCurrentOwner.current = workInProgress;
  let nextChildren;
  if (
    didCaptureError &&
    (!enableGetDerivedStateFromCatch ||
      typeof ctor.getDerivedStateFromCatch !== "function")
  ) {
    nextChildren = null;

    if (enableProfilerTimer) {
      stopBaseRenderTimerIfRunning();
    }
  } else {
    if (__DEV__) {
      ...
    } else {
    //  調(diào)用render函數(shù)獲取子元素
      nextChildren = instance.render();
    }
  }

  workInProgress.effectTag |= PerformedWork;
  if (didCaptureError) {
    reconcileChildrenAtExpirationTime(
      current,
      workInProgress,
      null,
      renderExpirationTime,
    );
    workInProgress.child = null;
  }
  //  把子元素轉(zhuǎn)換為Fiber類型
  //  如果子元素?cái)?shù)量大于一(即為數(shù)組)的時(shí)候,
  //  返回第一個(gè)Fiber類型子元素
  reconcileChildrenAtExpirationTime(
    current,
    workInProgress,
    nextChildren,
    renderExpirationTime,
  );
  //  處理state
  memoizeState(workInProgress, instance.state);
  //  處理props
  memoizeProps(workInProgress, instance.props);

  if (hasContext) {
    invalidateContextProvider(workInProgress, true);
  }

  //  返回Fiber類型的子元素給beginWork函數(shù),
  //  一直返回到workLoop函數(shù)(看上面的調(diào)用過(guò)程)
  return workInProgress.child;
}
workLoop

我們?cè)倩仡^看下workLoop和performUnitOfWork函數(shù)(看上面的函數(shù)調(diào)用過(guò)程),當(dāng)benginWork對(duì)不同類型組件完成相應(yīng)處理返回子元素后,workLoop繼續(xù)通過(guò)performUnitOfWork來(lái)調(diào)用benginWork對(duì)子元素進(jìn)行處理,從而遍歷虛擬DOM樹(shù):

function workLoop(isYieldy) {
  if (!isYieldy) {
    while (nextUnitOfWork !== null) {
      //  遍歷整棵虛擬DOM樹(shù)
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  } else {
    while (nextUnitOfWork !== null && !shouldYield()) {
      //  遍歷整棵虛擬DOM樹(shù)
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }

    if (enableProfilerTimer) {
      pauseActualRenderTimerIfRunning();
    }
  }
}
performUnitOfWork

這個(gè)函數(shù)很接近把虛擬DOM轉(zhuǎn)換為真實(shí)DOM的代碼啦,當(dāng)遍歷完成一顆虛擬DOM的子樹(shù)后(beginWork返回null,即已沒(méi)有子元素),調(diào)用completeUnitOfWork函數(shù)開(kāi)始轉(zhuǎn)換:

function performUnitOfWork(workInProgress: Fiber): Fiber | null {
  const current = workInProgress.alternate;

  startWorkTimer(workInProgress);

  let next;
  if (enableProfilerTimer) {
    if (workInProgress.mode & ProfileMode) {
      startBaseRenderTimer();
    }

    next = beginWork(current, workInProgress, nextRenderExpirationTime);

    if (workInProgress.mode & ProfileMode) {
      recordElapsedBaseRenderTimeIfRunning(workInProgress);
      stopBaseRenderTimerIfRunning();
    }
  } else {
    next = beginWork(current, workInProgress, nextRenderExpirationTime);
  }

  if (next === null) {
    next = completeUnitOfWork(workInProgress);
  }

  ReactCurrentOwner.current = null;

  return next;
}
completeUnitOfWork

此函數(shù)作用為先將當(dāng)前Fiber元素轉(zhuǎn)換為真實(shí)DOM節(jié)點(diǎn),然后在看有無(wú)兄弟節(jié)點(diǎn),若有則返回給上層函數(shù)處理完后再調(diào)用此函數(shù)進(jìn)行轉(zhuǎn)換;否則查看有無(wú)父節(jié)點(diǎn),若有則轉(zhuǎn)換父節(jié)點(diǎn)。

function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
  while (true) {
    const current = workInProgress.alternate;

    const returnFiber = workInProgress.return;
    const siblingFiber = workInProgress.sibling;

    if ((workInProgress.effectTag & Incomplete) === NoEffect) {
      //  調(diào)用completeWork轉(zhuǎn)換虛擬DOM
      let next = completeWork(
        current,
        workInProgress,
        nextRenderExpirationTime,
      );
      stopWorkTimer(workInProgress);
      resetExpirationTime(workInProgress, nextRenderExpirationTime);

      if (next !== null) {
        stopWorkTimer(workInProgress);
        return next;
      }

      //  處理完當(dāng)前節(jié)點(diǎn)后
      if (siblingFiber !== null) {
        //  如果有兄弟節(jié)點(diǎn),則將其返回
        return siblingFiber;
      } else if (returnFiber !== null) {
        //  沒(méi)有兄弟節(jié)點(diǎn)而有父節(jié)點(diǎn),則處理父節(jié)點(diǎn)
        workInProgress = returnFiber;
        continue;
      } else {
        return null;
      }
    } else {
      ...
  }
  
  return null;
}
completeWork

根據(jù)Fiber的類型進(jìn)行處理和拋出錯(cuò)誤,我們主要看HostComponent類型。對(duì)HostComponent類型的處理主要是更新屬性,然后通過(guò)createInstance創(chuàng)建DOM節(jié)點(diǎn),并添加進(jìn)父節(jié)點(diǎn)。

function completeWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
): Fiber | null {
  const newProps = workInProgress.pendingProps;

  if (enableProfilerTimer) {
    if (workInProgress.mode & ProfileMode) {
      recordElapsedActualRenderTime(workInProgress);
    }
  }

  switch (workInProgress.tag) {
    ...
    case HostComponent: {
      popHostContext(workInProgress);
      const rootContainerInstance = getRootHostContainer();
      const type = workInProgress.type;
      if (current !== null && workInProgress.stateNode != null) {
        //  更新屬性
        const oldProps = current.memoizedProps;
        const instance: Instance = workInProgress.stateNode;
        const currentHostContext = getHostContext();
        const updatePayload = prepareUpdate(
          instance,
          type,
          oldProps,
          newProps,
          rootContainerInstance,
          currentHostContext,
        );

        updateHostComponent(
          current,
          workInProgress,
          updatePayload,
          type,
          oldProps,
          newProps,
          rootContainerInstance,
          currentHostContext,
        );

        if (current.ref !== workInProgress.ref) {
          markRef(workInProgress);
        }
      } else {
        if (!newProps) {
          ...
          return null;
        }

        const currentHostContext = getHostContext();
        let wasHydrated = popHydrationState(workInProgress);
        if (wasHydrated) {
          if (
            prepareToHydrateHostInstance(
              workInProgress,
              rootContainerInstance,
              currentHostContext,
            )
          ) {
            markUpdate(workInProgress);
          }
        } else {
          //  創(chuàng)建并返回DOM元素
          let instance = createInstance(
            type,
            newProps,
            rootContainerInstance,
            currentHostContext,
            workInProgress,
          );

          //  將此DOM節(jié)點(diǎn)添加進(jìn)父節(jié)點(diǎn)
          appendAllChildren(instance, workInProgress);

          if (
            finalizeInitialChildren(
              instance,
              type,
              newProps,
              rootContainerInstance,
              currentHostContext,
            )
          ) {
            markUpdate(workInProgress);
          }
          workInProgress.stateNode = instance;
        }

        if (workInProgress.ref !== null) {
          // If there is a ref on a host node we need to schedule a callback
          markRef(workInProgress);
        }
      }
      return null;
    }
    ...
  }
}
createInstance
function createInstance(
  type: string,
  props: Props,
  rootContainerInstance: Container,
  hostContext: HostContext,
  internalInstanceHandle: Object,
): Instance {
  let parentNamespace: string;
  if (__DEV__) {
    ...
  } else {
    parentNamespace = ((hostContext: any): HostContextProd);
  }
  const domElement: Instance = createElement(
    type,
    props,
    rootContainerInstance,
    parentNamespace,
  );
  precacheFiberNode(internalInstanceHandle, domElement);
  updateFiberProps(domElement, props);
  return domElement;
}
createElement
function createElement(
  type: string,
  props: Object,
  rootContainerElement: Element | Document,
  parentNamespace: string,
): Element {
  let isCustomComponentTag;

  const ownerDocument: Document = getOwnerDocumentFromRootContainer(
    rootContainerElement,
  );
  let domElement: Element;
  let namespaceURI = parentNamespace;
  if (namespaceURI === HTML_NAMESPACE) {
    namespaceURI = getIntrinsicNamespace(type);
  }
  if (namespaceURI === HTML_NAMESPACE) {

    if (type === "script") {
      const div = ownerDocument.createElement("div");
      div.innerHTML = "                
閱讀需要支付1元查看
<