perf(ssr): avoid unnecessary await ticks when unrolling sync buffers
This commit is contained in:
parent
6bc0e0a31a
commit
30584bcc61
@ -20,7 +20,8 @@ import {
|
|||||||
isPromise,
|
isPromise,
|
||||||
isString,
|
isString,
|
||||||
isVoidTag,
|
isVoidTag,
|
||||||
ShapeFlags
|
ShapeFlags,
|
||||||
|
isArray
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
|
import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
|
||||||
import { ssrCompile } from './helpers/ssrCompile'
|
import { ssrCompile } from './helpers/ssrCompile'
|
||||||
@ -35,7 +36,7 @@ const {
|
|||||||
normalizeSuspenseChildren
|
normalizeSuspenseChildren
|
||||||
} = ssrUtils
|
} = ssrUtils
|
||||||
|
|
||||||
export type SSRBuffer = SSRBufferItem[]
|
export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean }
|
||||||
export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer>
|
export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer>
|
||||||
export type PushFn = (item: SSRBufferItem) => void
|
export type PushFn = (item: SSRBufferItem) => void
|
||||||
export type Props = Record<string, unknown>
|
export type Props = Record<string, unknown>
|
||||||
@ -68,6 +69,11 @@ export function createBuffer() {
|
|||||||
buffer.push(item)
|
buffer.push(item)
|
||||||
}
|
}
|
||||||
appendable = isStringItem
|
appendable = isStringItem
|
||||||
|
if (isPromise(item) || (isArray(item) && item.hasAsync)) {
|
||||||
|
// promise, or child buffer with async, mark as async.
|
||||||
|
// this allows skipping unnecessary await ticks during unroll stage
|
||||||
|
buffer.hasAsync = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,15 +16,33 @@ async function unrollBuffer(
|
|||||||
buffer: SSRBuffer,
|
buffer: SSRBuffer,
|
||||||
stream: Readable
|
stream: Readable
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
if (buffer.hasAsync) {
|
||||||
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
|
let item = buffer[i]
|
||||||
|
if (isPromise(item)) {
|
||||||
|
item = await item
|
||||||
|
}
|
||||||
|
if (isString(item)) {
|
||||||
|
stream.push(item)
|
||||||
|
} else {
|
||||||
|
await unrollBuffer(item, stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// sync buffer can be more efficiently unrolled without unnecessary await
|
||||||
|
// ticks
|
||||||
|
unrollBufferSync(buffer, stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unrollBufferSync(buffer: SSRBuffer, stream: Readable) {
|
||||||
for (let i = 0; i < buffer.length; i++) {
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
let item = buffer[i]
|
let item = buffer[i]
|
||||||
if (isPromise(item)) {
|
|
||||||
item = await item
|
|
||||||
}
|
|
||||||
if (isString(item)) {
|
if (isString(item)) {
|
||||||
stream.push(item)
|
stream.push(item)
|
||||||
} else {
|
} else {
|
||||||
await unrollBuffer(item, stream)
|
// since this is a sync buffer, child buffers are never promises
|
||||||
|
unrollBufferSync(item as SSRBuffer, stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,36 @@ import { SSRContext, renderComponentVNode, SSRBuffer } from './render'
|
|||||||
const { isVNode } = ssrUtils
|
const { isVNode } = ssrUtils
|
||||||
|
|
||||||
async function unrollBuffer(buffer: SSRBuffer): Promise<string> {
|
async function unrollBuffer(buffer: SSRBuffer): Promise<string> {
|
||||||
|
if (buffer.hasAsync) {
|
||||||
|
let ret = ''
|
||||||
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
|
let item = buffer[i]
|
||||||
|
if (isPromise(item)) {
|
||||||
|
item = await item
|
||||||
|
}
|
||||||
|
if (isString(item)) {
|
||||||
|
ret += item
|
||||||
|
} else {
|
||||||
|
ret += await unrollBuffer(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
} else {
|
||||||
|
// sync buffer can be more efficiently unrolled without unnecessary await
|
||||||
|
// ticks
|
||||||
|
return unrollBufferSync(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unrollBufferSync(buffer: SSRBuffer): string {
|
||||||
let ret = ''
|
let ret = ''
|
||||||
for (let i = 0; i < buffer.length; i++) {
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
let item = buffer[i]
|
let item = buffer[i]
|
||||||
if (isPromise(item)) {
|
|
||||||
item = await item
|
|
||||||
}
|
|
||||||
if (isString(item)) {
|
if (isString(item)) {
|
||||||
ret += item
|
ret += item
|
||||||
} else {
|
} else {
|
||||||
ret += await unrollBuffer(item as SSRBuffer)
|
// since this is a sync buffer, child buffers are never promises
|
||||||
|
ret += unrollBufferSync(item as SSRBuffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
Loading…
Reference in New Issue
Block a user