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