Skip to content

Commit 8897c6f

Browse files
committed
perf(runtime): optimize dom write scheduling
1 parent 45e99f6 commit 8897c6f

File tree

4 files changed

+48
-26
lines changed

4 files changed

+48
-26
lines changed

src/client/client-load-module.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,27 @@ import * as d from '../declarations';
22
import { BUILD } from '@build-conditionals';
33
import { consoleError } from './client-log';
44

5+
export const moduleCache = /*@__PURE__*/new Map<string, {[exportName: string]: d.ComponentConstructor}>();
56

6-
export const loadModule = (cmpMeta: d.ComponentRuntimeMeta, hostRef: d.HostRef, hmrVersionId?: string): Promise<d.ComponentConstructor> => {
7+
export const loadModule = (cmpMeta: d.ComponentRuntimeMeta, hostRef: d.HostRef, hmrVersionId?: string): Promise<d.ComponentConstructor> | d.ComponentConstructor => {
78
// loadModuleImport
8-
const bundleId = (BUILD.mode && typeof cmpMeta.$lazyBundleIds$ !== 'string')
9+
const exportName = cmpMeta.$tagName$.replace(/-/g, '_');
10+
const bundleId = ((BUILD.mode && typeof cmpMeta.$lazyBundleIds$ !== 'string')
911
? cmpMeta.$lazyBundleIds$[hostRef.$modeName$]
10-
: cmpMeta.$lazyBundleIds$;
11-
12+
: cmpMeta.$lazyBundleIds$) as string;
13+
const module = !BUILD.hotModuleReplacement ? moduleCache.get(bundleId) : false;
14+
if (module) {
15+
return module[exportName];
16+
}
1217
return import(
1318
/* webpackInclude: /\.entry\.js$/ */
1419
/* webpackExclude: /\.system\.entry\.js$/ */
1520
/* webpackMode: "lazy" */
1621
`./${bundleId}.entry.js${BUILD.hotModuleReplacement && hmrVersionId ? '?s-hmr=' + hmrVersionId : ''}`
17-
).then(importedModule => importedModule[cmpMeta.$tagName$.replace(/-/g, '_')], consoleError);
22+
).then(importedModule => {
23+
if (!BUILD.hotModuleReplacement) {
24+
moduleCache.set(bundleId, importedModule);
25+
}
26+
return importedModule[exportName];
27+
}, consoleError);
1828
};

src/client/client-task-queue.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ const queueDomWrites: d.RafCallback[] = [];
1212
const queueDomWritesLow: d.RafCallback[] = [];
1313

1414
const queueTask = (queue: d.RafCallback[]) => (cb: d.RafCallback) => {
15-
// queue dom reads
1615
queue.push(cb);
1716

1817
if (!queuePending) {

src/runtime/initialize-component.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { fireConnectedCallback } from './connected-callback';
1010
import { PROXY_FLAGS } from './runtime-constants';
1111

1212

13-
export const initializeComponent = async (elm: d.HostElement, hostRef: d.HostRef, cmpMeta: d.ComponentRuntimeMeta, hmrVersionId?: string, Cstr?: d.ComponentConstructor) => {
13+
export const initializeComponent = async (elm: d.HostElement, hostRef: d.HostRef, cmpMeta: d.ComponentRuntimeMeta, hmrVersionId?: string, Cstr?: any) => {
1414
// initializeComponent
1515
if ((BUILD.lazyLoad || BUILD.style) && (hostRef.$flags$ & HOST_FLAGS.hasInitializedComponent) === 0) {
1616
// we haven't initialized this element yet
@@ -31,7 +31,11 @@ export const initializeComponent = async (elm: d.HostElement, hostRef: d.HostRef
3131
// lazy loaded components
3232
// request the component's implementation to be
3333
// wired up with the host element
34-
Cstr = await loadModule(cmpMeta, hostRef, hmrVersionId);
34+
Cstr = loadModule(cmpMeta, hostRef, hmrVersionId);
35+
if (Cstr.then) {
36+
// Await creates a micro-task avoid if possible
37+
Cstr = await Cstr;
38+
}
3539
if ((BUILD.isDev || BUILD.isDebug) && !Cstr) {
3640
throw new Error(`Constructor for "${cmpMeta.$tagName$}#${hostRef.$modeName$}" was not found`);
3741
}
@@ -88,18 +92,19 @@ export const initializeComponent = async (elm: d.HostElement, hostRef: d.HostRef
8892

8993
// we've successfully created a lazy instance
9094
const ancestorComponent = hostRef.$ancestorComponent$;
95+
const schedule = () => scheduleUpdate(elm, hostRef, cmpMeta, true);
96+
9197
if (BUILD.lifecycle && BUILD.lazyLoad && ancestorComponent && ancestorComponent['s-lr'] === false && ancestorComponent['s-rc']) {
9298
// this is the intial load and this component it has an ancestor component
9399
// but the ancestor component has NOT fired its will update lifecycle yet
94100
// so let's just cool our jets and wait for the ancestor to continue first
95-
ancestorComponent['s-rc'].push(() =>
96-
// this will get fired off when the ancestor component
97-
// finally gets around to rendering its lazy self
98-
// fire off the initial update
99-
initializeComponent(elm, hostRef, cmpMeta)
100-
);
101+
102+
// this will get fired off when the ancestor component
103+
// finally gets around to rendering its lazy self
104+
// fire off the initial update
105+
ancestorComponent['s-rc'].push(schedule);
101106

102107
} else {
103-
scheduleUpdate(elm, hostRef, cmpMeta, true);
108+
schedule();
104109
}
105110
};

src/runtime/update-component.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,27 @@ import { HYDRATED_CLASS, PLATFORM_FLAGS } from './runtime-constants';
77
import { renderVdom } from './vdom/vdom-render';
88

99

10-
export const safeCall = async (instance: any, method: string, arg?: any) => {
10+
export const safeCall = (instance: any, method: string, arg?: any) => {
1111
if (instance && instance[method]) {
1212
try {
13-
await instance[method](arg);
13+
return instance[method](arg);
1414
} catch (e) {
1515
consoleError(e);
1616
}
1717
}
18+
return undefined;
1819
};
1920

20-
export const scheduleUpdate = async (elm: d.HostElement, hostRef: d.HostRef, cmpMeta: d.ComponentRuntimeMeta, isInitialLoad: boolean) => {
21+
const then = (promise: Promise<any>, thenFn: () => any) => {
22+
return promise && promise.then ? promise.then(thenFn) : thenFn();
23+
};
24+
25+
export const scheduleUpdate = (elm: d.HostElement, hostRef: d.HostRef, cmpMeta: d.ComponentRuntimeMeta, isInitialLoad: boolean) => {
2126
if (BUILD.taskQueue && BUILD.updatable) {
2227
hostRef.$flags$ |= HOST_FLAGS.isQueuedForUpdate;
2328
}
2429
const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm as any;
30+
let promise: Promise<void>;
2531
if (isInitialLoad) {
2632
if (BUILD.hostListener) {
2733
hostRef.$flags$ |= HOST_FLAGS.isListenReady;
@@ -32,31 +38,33 @@ export const scheduleUpdate = async (elm: d.HostElement, hostRef: d.HostRef, cmp
3238
}
3339
emitLifecycleEvent(elm, 'componentWillLoad');
3440
if (BUILD.cmpWillLoad) {
35-
await safeCall(instance, 'componentWillLoad');
41+
promise = safeCall(instance, 'componentWillLoad');
3642
}
3743

3844
} else {
3945
emitLifecycleEvent(elm, 'componentWillUpdate');
4046

4147
if (BUILD.cmpWillUpdate) {
42-
await safeCall(instance, 'componentWillUpdate');
48+
promise = safeCall(instance, 'componentWillUpdate');
4349
}
4450
}
4551

4652
emitLifecycleEvent(elm, 'componentWillRender');
4753
if (BUILD.cmpWillRender) {
48-
await safeCall(instance, 'componentWillRender');
54+
promise = then(promise, () => safeCall(instance, 'componentWillRender'));
4955
}
5056

5157
// there is no ancestorc omponent or the ancestor component
5258
// has already fired off its lifecycle update then
5359
// fire off the initial update
54-
if (BUILD.taskQueue) {
55-
writeTask(() => updateComponent(elm, hostRef, cmpMeta, instance, isInitialLoad));
56-
} else {
57-
// syncronuously write DOM
58-
updateComponent(elm, hostRef, cmpMeta, instance, isInitialLoad);
60+
const update = () => updateComponent(elm, hostRef, cmpMeta, instance, isInitialLoad);
61+
if (promise) {
62+
return promise.then(BUILD.taskQueue
63+
? () => writeTask(update)
64+
: update
65+
);
5966
}
67+
return update();
6068
};
6169

6270
const updateComponent = (elm: d.RenderNode, hostRef: d.HostRef, cmpMeta: d.ComponentRuntimeMeta, instance: any, isInitialLoad: boolean) => {

0 commit comments

Comments
 (0)