blog

Vueのソースコードを見てみよう 第2章:コンポーネント化のプロセス

まえがき\n\nVnodeの作成\n水和)このコードの行で、最初に見るべきことは、何が行われているかということです。\n最初に...

Jul 3, 2020 · 29 min. read
シェア

まえがき

Vueのソースコードを読み解く第2弾が始まります。Vueのプロセスをコンポーネント化するための初期化プロセスや、Vnodeの作成方法について説明します。また、vm.$vnodeとvm._vnodeの違いと関係についても説明します。vm._update(vm._render(), hydrating)前回の投稿では、vm.$mount関数が最終的に実行されることについて説明しました。

Vnodeを作成

src/core/instance/render.jsこのコードで最初に見るべきは、vm._render()です。

I.vm._render()あなたは何をしましたか?

まず、vm._render()の定義です。export function renderMixin (Vue: Class<Component>) {  //Vueクラスの初期化時にレンダー関数をマウントする   // install runtime convenience helpers   installRenderHelpers(Vue.prototype)   Vue.prototype.$nextTick = function (fn: Function) {     return nextTick(fn, this)   }   Vue.prototype._render = function (): VNode {     const vm: Component = this     const { render, _parentVnode } = vm.$options     if (_parentVnode) {       vm.$scopedSlots = normalizeScopedSlots(         _parentVnode.data.scopedSlots,         vm.$slots,         vm.$scopedSlots       )     }     // set parent vnode. this allows render functions to have access     // to the data on the placeholder node.     vm.$vnode = _parentVnode //最初のマウントは未定義     // render self     let vnode     try {       // There's no need to maintain a stack because all render fns are called       // separately from one another. Nested component's render fns are called       // when parent component is patched.       currentRenderingInstance = vm       vnode = render.call(vm._renderProxy, vm.$createElement)      //Vnodevmの具体的な実装.$createElement     } catch (e) {       handleError(e, vm, `render`)       // return error render result,       // or previous vnode to prevent render error causing blank component       /* istanbul ignore else */       if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {         try {           vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)         } catch (e) {           handleError(e, vm, `renderError`)           vnode = vm._vnode         }       } else {         vnode = vm._vnode       }     } finally {       currentRenderingInstance = null     }     // if the returned array contains only a single node, allow it  ルートノードは1つしかない。     if (Array.isArray(vnode) && vnode.length === 1) {       vnode = vnode[0]     }     // return empty vnode in case the render function errored out  只能有一个根节      if (!(vnode instanceof VNode)) {       if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) { //ルートノードは1つしかない。         warn(           'Multiple root nodes returned from render function. Render function ' +           'should return a single root node.',           vm         )       }       vnode = createEmptyVNode()     }     // set parent     vnode.parent = _parentVnode     return vnode   } }

export function renderMixin (Vue: Class<Component>) {  //Vue初期クラスの化時にレンダー関數をマウントする
  // install runtime convenience helpers
  installRenderHelpers(Vue.prototype)
  Vue.prototype.$nextTick = function (fn: Function) {
    return nextTick(fn, this)
  }
  Vue.prototype._render = function (): VNode {
    const vm: Component = this
    const { render, _parentVnode } = vm.$options
    if (_parentVnode) {
      vm.$scopedSlots = normalizeScopedSlots(
        _parentVnode.data.scopedSlots,
        vm.$slots,
        vm.$scopedSlots
      )
    }
    // set parent vnode. this allows render functions to have access
    // to the data on the placeholder node.
    vm.$vnode = _parentVnode //初期モビリティは未定義!
    // render self
    let vnode
    try {
      // There's no need to maintain a stack because all render fns are called
      // separately from one another. Nested component's render fns are called
      // when parent component is patched.
      currentRenderingInstance = vm
      vnode = render.call(vm._renderProxy, vm.$createElement)      //Vnodevm具体的な実践.$createElement
    } catch (e) {
      handleError(e, vm, `render`)
      // return error render result,
      // or previous vnode to prevent render error causing blank component
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
        try {
          vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
        } catch (e) {
          handleError(e, vm, `renderError`)
          vnode = vm._vnode
        }
      } else {
        vnode = vm._vnode
      }
    } finally {
      currentRenderingInstance = null
    }
    // if the returned array contains only a single node, allow it  ルートノードは1つしかない。
    if (Array.isArray(vnode) && vnode.length === 1) {
      vnode = vnode[0]
    }
    // return empty vnode in case the render function errored out  只能有一个根节 
    if (!(vnode instanceof VNode)) {
      if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) { //ルートノードは1つしかない。
        warn(
          'Multiple root nodes returned from render function. Render function ' +
          'should return a single root node.',
          vm
        )
      }
      vnode = createEmptyVNode()
    }
    // set parent
    vnode.parent = _parentVnode
    return vnode
  }
}

vm._update(vnode,hydrafting)コードを見るとわかりますが、vm._render()はVueのrenderMixinプロセスで作成され、まず各コードの詳細を見ずに、最終的に返されるvm._render()がvnodeであることがわかります。これらのステップのうちのいくつかに焦点を当てれば、詳細はとりあえず無視できます:

const { render, _parentVnode } = vm.$options1. vm.$optionsからrender関数と父親のvnodeを取得;

vm.$vnode = _parentVnode2、アノテーションは、このノードがレンダー関数がプレースホルダノードデータを取得できるようにすることは非常に明確です。<el-button></el-button>この後のコンポーネントの作成で、プレースホルダノードのデータを取得する方法について説明しますが、vm.$vnodeは父親ノード、つまり、element-uiなどのプレースホルダノードであることが理解できます。

vnode = render.call(vm._renderProxy, vm.$createElement)3、実際には、vnodeはvm.$createElementを通して生成され、vm.$createElementはしばしばh関数として参照されます:

new Vue({
  render: h => h(App),
}).$mount('#app')

vm._renderProxyに関しては、vm._init()の中で定義されます。

vm.$createElement

次に、vm.$createElementが何をするのかを見てみましょう。src/core/instance/render.jsこのコードでは、vm._init()を介して、vm.$createElementをinitRender(vm)で初期化しています。

export function initRender (vm: Component) {
  //.....some codes
  // bind the createElement fn to this instance
  // so that we get proper render context inside it.
  // args order: tag, data, children, normalizationType, alwaysNormalize
  // internal version is used by render functions compiled from templates
  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  // normalization is always applied for the public version, used in
  // user-written render functions.
  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
  // $attrs & $listeners are exposed for easier HOC creation.
  // they need to be reactive so that HOCs using them are always updated
  //... somecodes
}

createElement(vm, a, b, c, d, true)createElement(vm, a, b, c, d, true)vm.$createElementが実際に結果を返していることがわかります。

第三に、createElementと_createElement

3-1: createElement

src/core/vdom/create-elements.jscreateElement は .NET Framework で定義されています:

export function createElement ( // _createElement機能のカプセル化
  context: Component,
  tag: any,
  data: any,
  children: any,
  normalizationType: any,
  alwaysNormalize: boolean
): VNode | Array<VNode> {
  if (Array.isArray(data) || isPrimitive(data)) { //如果未传入data 则把变量值往下传递
    normalizationType = children
    children = data
    data = undefined
  }
  if (isTrue(alwaysNormalize)) {
    normalizationType = ALWAYS_NORMALIZE
  }
  return _createElement(context, tag, data, children, normalizationType)
}

このパラメータは、vueの公式ドキュメントのcreateElementパラメータで定義されているフィールドです。もちろん、App.vueでエクスポートされたアプリオブジェクトがタグとして渡されます。createElement()メソッドは、実際には、dataパラメータが渡されなかった場合に子要素などを下に移動させるだけで、誤ったパラメータ呼び出しが行われないようにしていることがわかります。本当のロジックは、戻り関数 _createElement にあります。

3-2: _createElement

src/core/vdom/create-elements.jscreateElementに関連する定義は、:

export function _createElement (
  context: Component,
  tag?: string | Class<Component> | Function | Object,
  data?: VNodeData,
  children?: any,
  normalizationType?: number
): VNode | Array<VNode> {
  if (isDef(data) && isDef((data: any).__ob__)) {
    process.env.NODE_ENV !== 'production' && warn(
      `Avoid using observed data object as vnode data: ${JSON.stringify(data)}
` +
      'Always create fresh vnode data objects in each render!',
      context
    )
    return createEmptyVNode()
  }
  // object syntax in v-bind
  if (isDef(data) && isDef(data.is)) {
    tag = data.is
  }
  if (!tag) {
    // in case of component :is set to falsy value
    return createEmptyVNode()
  }
  // warn against non-primitive key
  if (process.env.NODE_ENV !== 'production' &&
    isDef(data) && isDef(data.key) && !isPrimitive(data.key)
  ) {
    if (!__WEEX__ || !('@binding' in data.key)) {
      warn(
        'Avoid using non-primitive value as key, ' +
        'use string/number value instead.',
        context
      )
    }
  }
  // support single function children as default scoped slot
  if (Array.isArray(children) &&
    typeof children[0] === 'function'
  ) {
    data = data || {}
    data.scopedSlots = { default: children[0] }
    children.length = 0
  }
  if (normalizationType === ALWAYS_NORMALIZE) {
    children = normalizeChildren(children)
  } else if (normalizationType === SIMPLE_NORMALIZE) {
    children = simpleNormalizeChildren(children)
  }
  let vnode, ns
  if (typeof tag === 'string') {
    let Ctor
    ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
    if (config.isReservedTag(tag)) {
      // platform built-in elements
      if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) {
        warn(
          `The .native modifier for v-on is only valid on components but it was used on <${tag}>.`,
          context
        )
      }
      vnode = new VNode(
        config.parsePlatformTagName(tag), data, children,
        undefined, undefined, context
      )
    } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
      // component
      vnode = createComponent(Ctor, data, context, children, tag)
    } else {
      // unknown or unlisted namespaced elements
      // check at runtime because it may get assigned a namespace when its
      // parent normalizes children
      vnode = new VNode(
        tag, data, children,
        undefined, undefined, context
      )
    }
  } else {
    // direct component options / constructor
    vnode = createComponent(tag, data, context, children)
  }
  if (Array.isArray(vnode)) {
    return vnode
  } else if (isDef(vnode)) {
    if (isDef(ns)) applyNS(vnode, ns)
    if (isDef(data)) registerDeepBindings(data)
    return vnode
  } else {
    return createEmptyVNode()
  }
}

コードは長いので、いくつかの重要なポイントに集中してください:

1、childrenパラメータ処理:childrenパラメータは、決定するために入力パラメータのnormalisationTypeの値に応じて、2つの処理ケースを持っています。normalizeChildren(children)simpleNormalizeChildren(children)それはALWAYS_NORMALIZEコールである場合、それはSIMPLE_NORMALIZEである場合、呼び出し 。./helper/normolize-children.jsこれらの2つの関数は、下のディレクトリの同じレベルで定義されている、ここでは言うために詳細に展開しない、自分の理解を見てみましょう、1つは直接concat()シュートフラット配列であり、1つは配列に再帰的なプッシュです。

if (normalizationType === ALWAYS_NORMALIZE) {
    children = normalizeChildren(children)
} else if (normalizationType === SIMPLE_NORMALIZE) {
    children = simpleNormalizeChildren(children)
}

2、タグのタイプを決定する:1、文字列型であれば、ネイティブのhtmlタグかどうかを判断し続け、そうであれば、新しいVnode()、そうでなければ、タグはvue.component()またはローカルのコンポーネントコンポーネントを介して登録され、コンポーネントVnodeを生成するためにcreateComponent()に移動します;2、文字列型でない場合は、上記の状況と同様で、渡されたオブジェクトがAppの場合は、createComponent()メソッドでvnodeを生成します:

if (typeof tag === 'string') {
    let Ctor
    ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
    if (config.isReservedTag(tag)) {
      // platform built-in elements
      if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) {
        //生産環境
      }
      vnode = new VNode(
        config.parsePlatformTagName(tag), data, children,
        undefined, undefined, context
      )
    } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
      // component
      vnode = createComponent(Ctor, data, context, children, tag)
    } else {
      //不明な名前空間
    }
  } else {
    // direct component options / constructor
    vnode = createComponent(tag, data, context, children)
 }

3、Vnodeを返します。

createComponent(tag, data, context, children)ここでvnodeが生成されます。

createComponent()

export function createComponent (
  Ctor: Class<Component> | Function | Object | void, //着信オブジェクト
  data: ?VNodeData,
  context: Component,
  children: ?Array<VNode>,
  tag?: string
): VNode | Array<VNode> | void {
  if (isUndef(Ctor)) {
    return
  }
  const baseCtor = context.$options._base  //は、基本クラスのコンストラクタとして、Vueそのものである。
  // plain options object: turn it into a constructor
  if (isObject(Ctor)) {
    Ctor = baseCtor.extend(Ctor) // Vueを理解するためにコンストラクタに変換する.extend 
  }
  // if at this stage it's not a constructor or an async component factory,
  // reject.
  if (typeof Ctor !== 'function') {
    if (process.env.NODE_ENV !== 'production') {
      warn(`Invalid Component definition: ${String(Ctor)}`, context)
    }
    return
  }
  // async component
  let asyncFactory
  if (isUndef(Ctor.cid)) {
    asyncFactory = Ctor
    Ctor = resolveAsyncComponent(asyncFactory, baseCtor)
    if (Ctor === undefined) {
      // return a placeholder node for async component, which is rendered
      // as a comment node but preserves all the raw information for the node.
      // the information will be used for async server-rendering and hydration.
      return createAsyncPlaceholder(
        asyncFactory,
        data,
        context,
        children,
        tag
      )
    }
  }
  data = data || {}
  // resolve constructor options in case global mixins are applied after
  // component constructor creation
  resolveConstructorOptions(Ctor)
  // transform component v-model data into props & events
  if (isDef(data.model)) {
    transformModel(Ctor.options, data)
  }
  // extract props
  const propsData = extractPropsFromVNodeData(data, Ctor, tag)
  // functional component
  if (isTrue(Ctor.options.functional)) {
    return createFunctionalComponent(Ctor, propsData, data, context, children)
  }
  // extract listeners, since these needs to be treated as
  // child component listeners instead of DOM listeners
  const listeners = data.on
  // replace with listeners with .native modifier
  // so it gets processed during parent component patch.
  data.on = data.nativeOn
  if (isTrue(Ctor.options.abstract)) {
    // abstract components do not keep anything
    // other than props & listeners & slot
    // work around flow
    const slot = data.slot
    data = {}
    if (slot) {
      data.slot = slot
    }
  }
  // install component management hooks onto the placeholder node
  installComponentHooks(data) //
  // return a placeholder vnode
  const name = Ctor.options.name || tag
  const vnode = new VNode(
    `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
    data, undefined, undefined, undefined, context,
    { Ctor, propsData, listeners, tag, children },
    asyncFactory
  )
  // Weex specific: invoke recycle-list optimized @render function for
  // extracting cell-slot template.
  // https://.//--///nt
  /* istanbul ignore if */
  if (__WEEX__ && isRecyclableComponent(vnode)) {
    return renderRecyclableComponentTemplate(vnode)
  }
  return vnode
}

これらのハイライトのいくつかに注目してください:

つまり、Vue.extend() が行うことです。

Ctor = baseCtor.extend(Ctor)vue自身を参照する最初のレンダリングは、次の場所で定義されています。では、vue.extend()は、appオブジェクトに対して具体的に何を行うのでしょうか。vue.extendは、次の場所で定義されています:

Vue.cid = 0
let cid = 1
Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this //Vueの静的メソッドを指す
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) { //单例模式,如果是复用的组件,那么 直接返回缓存在cachedCtors[SuperId]サブ
      return cachedCtors[SuperId]
    }
    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name) // コンポーネントのname属性をチェックする
    }
    const Sub = function VueComponent (options) {
      this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype) //プロトタイプの継承
    Sub.prototype.constructor = Sub //ポイント・コンストラクタをサブに戻す。
    Sub.cid = cid++
    Sub.options = mergeOptions(  //マージオプション
      Super.options,
      extendOptions
    )
    Sub['super'] = Super //superVueを指す
    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }
    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use
    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }
    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)
    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
}

Vue.extend()が行うことは、おおよそ以下の5つです。

cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})1.パフォーマンスを最適化するために、このコンポーネントインスタンスのコンストラクタ・メソッド属性を作成します:

if (cachedCtors[SuperId]) { //单例模式,如果是复用的组件,那么 直接返回缓存在cachedCtors[SuperId]サブ
 return cachedCtors[SuperId]
}

2.コンポーネントのコンストラクタを作成するプロトタイプ継承パターン:

const Sub = function VueComponent (options) {
 this._init(options)//Vueを探す_init
}
Sub.prototype = Object.create(Super.prototype) //プロトタイプの継承
Sub.prototype.constructor = Sub //ポイント・コンストラクタをサブに戻す。
Sub.cid = cid++
Sub.options = mergeOptions(  //マージオプション
 Super.options,
    extendOptions
)
Sub['super'] = Super //superVueを指す

object.defineProperty3.パッチのインスタンス化がここを呼び出さないように、双方向のデータバインディングを進めます:

    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

4.Vueの親クラスのグローバルメソッドを継承します:

    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

5.オブジェクトをキャッシュして返します:

    cachedCtors[SuperId] = Sub
    return Sub

createComponentあとは

const propsData = extractPropsFromVNodeData(data, Ctor, tag)1、このコードは、プレースホルダ・ノードからカスタムpropsプロパティを取得し、後でそれをサブコンポーネントに渡すための鍵となります。

2.機能部品:

if (isTrue(Ctor.options.functional)) {
 return createFunctionalComponent(Ctor, propsData, data, context, children)
}

installComponentHooks(data)3は、別のキーは、フック関数の上に登録されたコンポーネントは、フック関数は、以下の同じファイルに定義されています:initに分かれて、プリパッチ、挿入、4つのフック関数を破棄し、パッチプロセスが具体的に導入されます:

const hooksToMerge = Object.keys(componentVNodeHooks)
function installComponentHooks (data: VNodeData) {
  const hooks = data.hook || (data.hook = {})
  for (let i = 0; i < hooksToMerge.length; i++) {
    const key = hooksToMerge[i]
    const existing = hooks[key]
    const toMerge = componentVNodeHooks[key]
    if (existing !== toMerge && !(existing && existing._merged)) {
      hooks[key] = existing ? mergeHook(toMerge, existing) : toMerge
    }
  }
}

4, new Vnode() & retrun vnode.

const vnode = new VNode(
    `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
    data, undefined, undefined, undefined, context,
    { Ctor, propsData, listeners, tag, children },
    asyncFactory
)
return vnode

コンポーネントのコンストラクタなどが、コンストラクタが渡されたオブジェクトの中に置かれているのがわかります。

つまり、この時点でcreateComponent()の処理はおおよそ終わっています。

Virtual-Dom

vnodeの作成については半日話しましたが、vnodeクラスの実装については話しませんでしたが、最後にvnodeの話をしたのには理由があり、vnodeを作成するには多すぎる状況であり、上記をまず広め、最後にvnodeを集めて、犬の印象を深めることができればと思います。

5-1.なぜVnodeを使うのですか?

1、本物のDOMを作るための高いコスト

実際のDOMノードが多くの属性を実装しているのに対し、vnodeは必要な一部の属性のみを実装しており、vnodeを作成するコストは比較的低くなっています。そのため、vnodeを作成することで、要件そのものにより集中することができます。

2、複数のブラウザの再描画と再フローのトリガー

vnodeの使用は、バッファを追加するのと同等なので、すべてのノードの変更によってもたらされるデータの変更は、最初のvnodeで変更され、その後、ブラウザの再描画とリフローを減らすために、変更するには、DOMツリーに一度集中ノード内のすべての差の後に差分。これは、キューを更新するウォッチャーのレンダリング、コンポーネントの更新など、詳細な応答の原理の章で詳細に説明されます〜〜。

-2中間マージンなし、Class Vnode{}

src/core/vdom/vnode.jsVnode クラスは .NET で定義されています:

export default class VNode {
  tag: string | void;
  data: VNodeData | void;
  children: ?Array<VNode>;
  text: string | void;
  elm: Node | void;
  ns: string | void;
  context: Component | void; // rendered in this component's scope
  key: string | number | void;
  componentOptions: VNodeComponentOptions | void;
  componentInstance: Component | void; // component instance
  parent: VNode | void; // component placeholder node
  // strictly internal
  raw: boolean; // contains raw HTML? (server only)
  isStatic: boolean; // hoisted static node
  isRootInsert: boolean; // necessary for enter transition check
  isComment: boolean; // empty comment placeholder?
  isCloned: boolean; // is a cloned node?
  isOnce: boolean; // is a v-once node?
  asyncFactory: Function | void; // async component factory function
  asyncMeta: Object | void;
  isAsyncPlaceholder: boolean;
  ssrContext: Object | void;
  fnContext: Component | void; // real context vm for functional nodes
  fnOptions: ?ComponentOptions; // for SSR caching
  devtoolsMeta: ?Object; // used to store functional render context for devtools
  fnScopeId: ?string; // functional scope id support
  constructor (
    tag?: string,
    data?: VNodeData,
    children?: ?Array<VNode>,
    text?: string,
    elm?: Node,
    context?: Component,
    componentOptions?: VNodeComponentOptions,
    asyncFactory?: Function
  ) {
    //somecodes
  }
  // DEPRECATED: alias for componentInstance for backwards compat.
  /* istanbul ignore next */
  get child (): Component | void {
    return this.componentInstance
  }
}

このVnodeクラスは非常に長くなっているようですが、実際のdom nodeはこれよりも複雑で巨大であり、その属性は、当面は気にすることができないものもありますが、コンストラクタに焦点を当てています:

  constructor (
    tag?: string,
    data?: VNodeData,
    children?: ?Array<VNode>,
    text?: string,
    elm?: Node,
    context?: Component,
    componentOptions?: VNodeComponentOptions,
    asyncFactory?: Function
  ) {
    this.tag = tag
    this.data = data
    this.children = children
    this.text = text
    this.elm = elm
    this.ns = undefined
    this.context = context
    this.fnContext = undefined
    this.fnOptions = undefined
    this.fnScopeId = undefined
    this.key = data && data.key
    this.componentOptions = componentOptions
    this.componentInstance = undefined
    this.parent = undefined
    this.raw = false
    this.isStatic = false
    this.isRootInsert = true
    this.isComment = false
    this.isCloned = false
    this.isOnce = false
    this.asyncFactory = asyncFactory
    this.asyncMeta = undefined
    this.isAsyncPlaceholder = false
  }

createComponent() で作成された vnode に渡されたパラメータを比較します:

const vnode = new VNode(
    `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
    data, undefined, undefined, undefined, context,
    { Ctor, propsData, listeners, tag, children },
    asyncFactory
)

概要

"このセクションの焦点は、vnodeの作成方法と、状況によって異なる作成方法です。 今は詳細を掘り下げてはいけませんが、後々徐々に広げていくことで、振り返った時にスッキリと理解できるようになります!振り返ればわかるようになる!"

最後にちょっと宣伝。

SMSビジネスや番号認証機能が必要なお偉方は、こちらをご覧ください! 事業者の公式プラットフォーム!中間マージンなし

Read next

Laravel redis キューベースの解析

非同期実行: コード実行の一部は非常に時間がかかります。レスポンス速度を向上させ、接続リソースの過剰な占有を避けるために、コードのこの部分をキューに入れ、非同期実行することができます。 エラーの再試行:いくつかのタスクの正常な実行を確保するためには、タスクの実行エラーが正常に処理されるまで、またはエラーの実行のキャンセル後にN回以上再試行する時間の期間を遅らせることができる場合は、キュー実行にタスクを置くことができます。 ここでは、分散...

Jul 3, 2020 · 5 min read