]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: simplify time-slicing implementation
authorEvan You <yyx990803@gmail.com>
Fri, 9 Nov 2018 23:01:58 +0000 (18:01 -0500)
committerEvan You <yyx990803@gmail.com>
Fri, 9 Nov 2018 23:01:58 +0000 (18:01 -0500)
packages/runtime-core/src/createRenderer.ts
packages/scheduler/src/experimental.ts

index b1ecaafca16d659f1bb246038b58ed61186f0543..a6f750c025ce57a348debaec24e13ee2724f0639 100644 (file)
@@ -10,7 +10,8 @@ import {
   handleSchedulerError,
   nextTick,
   queuePostCommitCb,
-  flushPostCommitCbs
+  flushPostCommitCbs,
+  queueNodeOp
 } from '@vue/scheduler'
 import { VNodeFlags, ChildrenFlags } from './flags'
 import { EMPTY_OBJ, reservedPropRE, isString } from '@vue/shared'
@@ -110,9 +111,9 @@ export function createRenderer(options: RendererOptions) {
     refNode: RenderNode | null
   ) {
     if (refNode === null) {
-      platformAppendChild(container, newNode)
+      queueNodeOp([platformAppendChild, container, newNode])
     } else {
-      platformInsertBefore(container, newNode, refNode)
+      queueNodeOp([platformInsertBefore, newNode, refNode])
     }
   }
 
@@ -662,7 +663,7 @@ export function createRenderer(options: RendererOptions) {
     const el = (nextVNode.el = prevVNode.el) as RenderNode
     const nextText = nextVNode.children
     if (nextText !== prevVNode.children) {
-      platformSetText(el, nextText as string)
+      queueNodeOp([platformSetText, el, nextText])
     }
   }
 
@@ -1162,7 +1163,7 @@ export function createRenderer(options: RendererOptions) {
             removeVNode(children as MountedVNode, container)
             break
           case ChildrenFlags.NO_CHILDREN:
-            platformRemoveChild(container, el)
+            queueNodeOp([platformRemoveChild, container, el])
             break
           default:
             for (let i = 0; i < (children as MountedVNode[]).length; i++) {
@@ -1170,7 +1171,7 @@ export function createRenderer(options: RendererOptions) {
             }
         }
       } else {
-        platformRemoveChild(container, el)
+        queueNodeOp([platformRemoveChild, container, el])
       }
     }
     ;(vnode as any).el = null
@@ -1183,7 +1184,7 @@ export function createRenderer(options: RendererOptions) {
   ) {
     unmountArrayChildren(children)
     if (refNode === null) {
-      platformClearContent(container)
+      queueNodeOp([platformClearContent, container])
     } else {
       for (let i = 0; i < children.length; i++) {
         removeVNode(children[i], container)
index 118f3bc819500991402c5f19d213398388e8ab17..6f2a0eb737628bacfa7bc076dfd9d5837edfac3e 100644 (file)
@@ -1,18 +1,27 @@
 // TODO infinite updates detection
 
-import { Op, setCurrentOps } from './patchNodeOps'
+// import { Op } from './patchNodeOps'
+
+type Op = [Function, ...any[]]
+
+const enum Priorities {
+  NORMAL = 500
+}
+
+const enum JobStatus {
+  PENDING_PATCH = 1,
+  PENDING_COMMIT,
+  COMMITED
+}
 
 interface Job extends Function {
+  status: JobStatus
   ops: Op[]
   post: Function[]
   cleanup: Function | null
   expiration: number
 }
 
-const enum Priorities {
-  NORMAL = 500
-}
-
 type ErrorHandler = (err: Error) => any
 
 let currentJob: Job | null = null
@@ -93,30 +102,15 @@ let hasPendingFlush = false
 
 export function queueJob(rawJob: Function) {
   const job = rawJob as Job
-  job.ops = job.ops || []
-  job.post = job.post || []
   // 1. let's see if this invalidates any work that
   // has already been done.
-  const commitIndex = commitQueue.indexOf(job)
-  if (commitIndex > -1) {
-    // invalidated. remove from commit queue
-    // and move it back to the patch queue
-    commitQueue.splice(commitIndex, 1)
+  if (job.status === JobStatus.PENDING_COMMIT) {
+    // pending commit job invalidated
     invalidateJob(job)
-    // With varying priorities we should insert job at correct position
-    // based on expiration time.
-    for (let i = 0; i < patchQueue.length; i++) {
-      if (job.expiration < patchQueue[i].expiration) {
-        patchQueue.splice(i, 0, job)
-        break
-      }
-    }
-  } else if (patchQueue.indexOf(job) === -1) {
+  } else if (job.status !== JobStatus.PENDING_PATCH) {
     // a new job
-    job.expiration = getNow() + Priorities.NORMAL
-    patchQueue.push(job)
+    insertNewJob(job)
   }
-
   if (!hasPendingFlush) {
     hasPendingFlush = true
     flushAfterMicroTask()
@@ -135,9 +129,18 @@ export function flushPostCommitCbs() {
   // post commit hooks (updated, mounted)
   // this queue is flushed in reverse becuase these hooks should be invoked
   // child first
-  let job
-  while ((job = postCommitQueue.pop())) {
-    job()
+  let i = postCommitQueue.length
+  while (i--) {
+    postCommitQueue[i]()
+  }
+  postCommitQueue.length = 0
+}
+
+export function queueNodeOp(op: Op) {
+  if (currentJob) {
+    currentJob.ops.push(op)
+  } else {
+    applyOp(op)
   }
 }
 
@@ -160,13 +163,10 @@ function flush(): void {
 
   if (patchQueue.length === 0) {
     // all done, time to commit!
-    while ((job = commitQueue.shift())) {
-      commitJob(job)
-      if (job.post) {
-        postCommitQueue.push(...job.post)
-        job.post.length = 0
-      }
+    for (let i = 0; i < commitQueue.length; i++) {
+      commitJob(commitQueue[i])
     }
+    commitQueue.length = 0
     flushPostCommitCbs()
     // some post commit hook triggered more updates...
     if (patchQueue.length > 0) {
@@ -191,31 +191,61 @@ function flush(): void {
   }
 }
 
+function insertNewJob(job: Job) {
+  job.ops = job.ops || []
+  job.post = job.post || []
+  job.expiration = getNow() + Priorities.NORMAL
+  patchQueue.push(job)
+  job.status = JobStatus.PENDING_PATCH
+}
+
+function invalidateJob(job: Job) {
+  job.ops.length = 0
+  job.post.length = 0
+  if (job.cleanup) {
+    job.cleanup()
+    job.cleanup = null
+  }
+  // remove from commit queue
+  // and move it back to the patch queue
+  commitQueue.splice(commitQueue.indexOf(job), 1)
+  // With varying priorities we should insert job at correct position
+  // based on expiration time.
+  for (let i = 0; i < patchQueue.length; i++) {
+    if (job.expiration < patchQueue[i].expiration) {
+      patchQueue.splice(i, 0, job)
+      break
+    }
+  }
+  job.status = JobStatus.PENDING_PATCH
+}
+
 function patchJob(job: Job) {
   // job with existing ops means it's already been patched in a low priority queue
   if (job.ops.length === 0) {
-    setCurrentOps(job.ops)
     currentJob = job
     job.cleanup = job()
     currentJob = null
-    setCurrentOps(null)
     commitQueue.push(job)
+    job.status = JobStatus.PENDING_COMMIT
   }
 }
 
-function commitJob({ ops }: Job) {
+function commitJob(job: Job) {
+  const { ops, post } = job
   for (let i = 0; i < ops.length; i++) {
-    const [fn, ...args] = ops[i]
-    fn(...args)
+    applyOp(ops[i])
   }
   ops.length = 0
+  // queue post commit cbs
+  if (post) {
+    postCommitQueue.push(...post)
+    post.length = 0
+  }
+  job.status = JobStatus.COMMITED
 }
 
-function invalidateJob(job: Job) {
-  job.ops.length = 0
-  job.post.length = 0
-  if (job.cleanup) {
-    job.cleanup()
-    job.cleanup = null
-  }
+function applyOp(op: Op) {
+  const fn = op[0]
+  fn(op[1], op[2], op[3])
 }