Просмотр исходного кода

refactor ssr render context into separate class

Evan You 9 лет назад
Родитель
Сommit
05b070fd41
2 измененных файлов с 114 добавлено и 68 удалено
  1. 109 0
      src/server/render-context.js
  2. 5 68
      src/server/render.js

+ 109 - 0
src/server/render-context.js

@@ -0,0 +1,109 @@
+/* @flow */
+
+type RenderState = {
+  type: 'Element';
+  rendered: number;
+  total: number;
+  endTag: string;
+  children: Array<VNode>;
+} | {
+  type: 'Component';
+  prevActive: Component;
+} | {
+  type: 'ComponentWithCache';
+  buffer: Array<string>;
+  bufferIndex: number;
+  key: string;
+}
+
+export class RenderContext {
+  activeInstance: Component;
+  renderStates: Array<RenderState>;
+  write: (text: string, next: Function) => void;
+  renderNode: (node: VNode, isRoot: boolean, context: RenderContext) => void;
+  next: () => void;
+  done: () => void;
+
+  modules: Array<() => ?string>;
+  directives: Object;
+  isUnaryTag: (tag: string) => boolean;
+
+  cache: any;
+  get: ?(key: string, cb: Function) => void;
+  has: ?(key: string, cb: Function) => void;
+
+  constructor (options: Object) {
+    this.activeInstance = options.activeInstance
+    this.renderStates = []
+
+    this.write = options.write
+    this.done = options.done
+    this.renderNode = options.renderNode
+
+    this.isUnaryTag = options.isUnaryTag
+    this.modules = options.modules
+    this.directives = options.directives
+
+    const cache = options.cache
+    if (cache && (!cache.get || !cache.set)) {
+      throw new Error('renderer cache must implement at least get & set.')
+    }
+    this.cache = cache
+    this.get = cache && normalizeAsync(cache, 'get')
+    this.has = cache && normalizeAsync(cache, 'has')
+
+    this.next = this.next.bind(this)
+  }
+
+  next () {
+    const lastState = this.renderStates[this.renderStates.length - 1]
+    if (!lastState) {
+      return this.done()
+    }
+    switch (lastState.type) {
+      case 'Element':
+        const { children, total } = lastState
+        const rendered = lastState.rendered++
+        if (rendered < total) {
+          this.renderNode(children[rendered], false, this)
+        } else {
+          this.renderStates.pop()
+          this.write(lastState.endTag, this.next)
+        }
+        break
+      case 'Component':
+        this.renderStates.pop()
+        this.activeInstance = lastState.prevActive
+        this.next()
+        break
+      case 'ComponentWithCache':
+        this.renderStates.pop()
+        const { buffer, bufferIndex, key } = lastState
+        const result = buffer[bufferIndex]
+        this.cache.set(key, result)
+        if (bufferIndex === 0) {
+          // this is a top-level cached component,
+          // exit caching mode.
+          this.write.caching = false
+        } else {
+          // parent component is also being cached,
+          // merge self into parent's result
+          buffer[bufferIndex - 1] += result
+        }
+        buffer.length = bufferIndex
+        this.next()
+        break
+    }
+  }
+}
+
+function normalizeAsync (cache, method) {
+  const fn = cache[method]
+  if (!fn) {
+    return
+  } else if (fn.length > 1) {
+    return (key, cb) => fn.call(cache, key, cb)
+  } else {
+    return (key, cb) => cb(fn.call(cache, key))
+  }
+}

+ 5 - 68
src/server/render.js

@@ -1,9 +1,9 @@
 /* @flow */
 
 import { escape } from 'he'
+import { RenderContext } from './render-context'
 import { compileToFunctions } from 'web/compiler/index'
 import { createComponentInstanceForVnode } from 'core/vdom/create-component'
-import { noop } from 'shared/util'
 
 let warned = Object.create(null)
 const warnOnce = msg => {
@@ -13,17 +13,6 @@ const warnOnce = msg => {
   }
 }
 
-const normalizeAsync = (cache, method) => {
-  const fn = cache[method]
-  if (!fn) {
-    return
-  } else if (fn.length > 1) {
-    return (key, cb) => fn.call(cache, key, cb)
-  } else {
-    return (key, cb) => cb(fn.call(cache, key))
-  }
-}
-
 const compilationCache = Object.create(null)
 const normalizeRender = vm => {
   const { render, template } = vm.$options
@@ -202,76 +191,24 @@ function renderStartingTag (node: VNode, context) {
   return markup + '>'
 }
 
-const nextFactory = context => function next () {
-  const lastState = context.renderStates.pop()
-  if (!lastState) {
-    context.done()
-    // cleanup context, avoid leakage
-    context = (null: any)
-    return
-  }
-  switch (lastState.type) {
-    case 'Component':
-      context.activeInstance = lastState.prevActive
-      next()
-      break
-    case 'Element':
-      const { children, total } = lastState
-      const rendered = lastState.rendered++
-      if (rendered < total) {
-        context.renderStates.push(lastState)
-        renderNode(children[rendered], false, context)
-      } else {
-        context.write(lastState.endTag, next)
-      }
-      break
-    case 'ComponentWithCache':
-      const { buffer, bufferIndex, key } = lastState
-      const result = buffer[bufferIndex]
-      context.cache.set(key, result)
-      if (bufferIndex === 0) {
-        // this is a top-level cached component,
-        // exit caching mode.
-        context.write.caching = false
-      } else {
-        // parent component is also being cached,
-        // merge self into parent's result
-        buffer[bufferIndex - 1] += result
-      }
-      buffer.length = bufferIndex
-      next()
-      break
-  }
-}
-
 export function createRenderFunction (
   modules: Array<Function>,
   directives: Object,
   isUnaryTag: Function,
   cache: any
 ) {
-  if (cache && (!cache.get || !cache.set)) {
-    throw new Error('renderer cache must implement at least get & set.')
-  }
-
-  const get = cache && normalizeAsync(cache, 'get')
-  const has = cache && normalizeAsync(cache, 'has')
-
   return function render (
     component: Component,
     write: (text: string, next: Function) => void,
     done: Function
   ) {
     warned = Object.create(null)
-    const context = {
+    const context = new RenderContext({
       activeInstance: component,
-      renderStates: [],
-      next: noop, // for flow
-      write, done,
+      write, done, renderNode,
       isUnaryTag, modules, directives,
-      cache, get, has
-    }
-    context.next = nextFactory(context)
+      cache
+    })
     normalizeRender(component)
     renderNode(component._render(), true, context)
   }