@player-ui/async-node-plugin 0.13.0-next.1 → 0.13.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
"types"
|
|
7
7
|
],
|
|
8
8
|
"name": "@player-ui/async-node-plugin",
|
|
9
|
-
"version": "0.13.0-next.
|
|
9
|
+
"version": "0.13.0-next.2",
|
|
10
10
|
"main": "dist/cjs/index.cjs",
|
|
11
11
|
"peerDependencies": {
|
|
12
|
-
"@player-ui/player": "0.13.0-next.
|
|
12
|
+
"@player-ui/player": "0.13.0-next.2"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@player-ui/reference-assets-plugin": "workspace:*",
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { bench, BenchOptions, describe } from "vitest";
|
|
2
|
+
import { AsyncNodePlugin, AsyncNodePluginPlugin } from "..";
|
|
3
|
+
import { Flow, Player } from "@player-ui/player";
|
|
4
|
+
|
|
5
|
+
const asyncBenchFlow: Flow = {
|
|
6
|
+
id: "test-flow",
|
|
7
|
+
views: [
|
|
8
|
+
{
|
|
9
|
+
id: "my-view",
|
|
10
|
+
type: "view",
|
|
11
|
+
values: [
|
|
12
|
+
{
|
|
13
|
+
id: "nodeId",
|
|
14
|
+
async: "true",
|
|
15
|
+
flatten: true,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
navigation: {
|
|
21
|
+
BEGIN: "FLOW_1",
|
|
22
|
+
FLOW_1: {
|
|
23
|
+
startState: "VIEW_1",
|
|
24
|
+
VIEW_1: {
|
|
25
|
+
state_type: "VIEW",
|
|
26
|
+
ref: "my-view",
|
|
27
|
+
transitions: {
|
|
28
|
+
"*": "END_DONE",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
END_DONE: {
|
|
32
|
+
state_type: "END",
|
|
33
|
+
outcome: "done",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Benchmark tests for async node resolution. Each test spins up player and resolves all but the last async node to be setup.
|
|
40
|
+
// This is to make tests results easier to compare. If test results across different node counts are similar than we know that resolving additional async nodes will not have significant performance impact.
|
|
41
|
+
describe("async node benchmarks", () => {
|
|
42
|
+
const asyncNodes = [1, 5, 10, 50, 100];
|
|
43
|
+
|
|
44
|
+
asyncNodes.forEach((nodeCount) => {
|
|
45
|
+
// Promise for when player reaches a completed state.
|
|
46
|
+
let playerCompletePromise: Promise<unknown>;
|
|
47
|
+
// Function to resolve the async node. Resolves the promise for the `onAsyncNode` hook.
|
|
48
|
+
let resolveAsyncNode: () => void;
|
|
49
|
+
|
|
50
|
+
// Setup function for spinning up player and setting up the above promise and function.
|
|
51
|
+
// Using a setup function also takes all the overhead of the setup itself out of the perf benchmark.
|
|
52
|
+
const setupPlayer = () => {
|
|
53
|
+
const asyncNodePlugin = new AsyncNodePlugin({
|
|
54
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let completeSetup: (value?: unknown) => void = () => {};
|
|
58
|
+
const setupPromise = new Promise((res) => {
|
|
59
|
+
completeSetup = res;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
let lastCreatedNodeIndex = -1;
|
|
63
|
+
asyncNodePlugin.hooks.onAsyncNode.tap("bench", () => {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
const nodeNumber = lastCreatedNodeIndex + 1;
|
|
66
|
+
// Setup the resolve function to add a text asset and another async node.
|
|
67
|
+
resolveAsyncNode = () => {
|
|
68
|
+
lastCreatedNodeIndex = nodeNumber;
|
|
69
|
+
resolve([
|
|
70
|
+
{
|
|
71
|
+
asset: {
|
|
72
|
+
id: `bench-${nodeNumber}`,
|
|
73
|
+
type: "text",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: `another-async-${nodeNumber}`,
|
|
78
|
+
async: true,
|
|
79
|
+
flatten: true,
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// If this is not the last node to be added for this test, resolve it immediately, otherwise resolve the setup promise.
|
|
85
|
+
if (nodeNumber + 1 < nodeCount) {
|
|
86
|
+
resolveAsyncNode();
|
|
87
|
+
} else {
|
|
88
|
+
completeSetup();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const player = new Player({ plugins: [asyncNodePlugin] });
|
|
94
|
+
|
|
95
|
+
player.hooks.view.tap("bench", (fc) => {
|
|
96
|
+
fc.hooks.onUpdate.tap("bench", () => {
|
|
97
|
+
// Since the created index should go up to `nodeCount - 1` we wait for that to be true before transitioning player to its end state.
|
|
98
|
+
if (lastCreatedNodeIndex < nodeCount - 1) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const state = player.getState();
|
|
103
|
+
|
|
104
|
+
if (state.status !== "in-progress") {
|
|
105
|
+
throw new Error("benchmark failed");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
state.controllers.flow.transition("END");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
playerCompletePromise = player.start(asyncBenchFlow);
|
|
113
|
+
|
|
114
|
+
return setupPromise;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// The bench setup function. This gets called once before all iterations of the test are run
|
|
118
|
+
const setup: BenchOptions["setup"] = (task) => {
|
|
119
|
+
// Add setup to the before each and wait on it to finish before starting a test run.
|
|
120
|
+
task.opts.beforeEach = async () => {
|
|
121
|
+
await setupPlayer();
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
bench(
|
|
126
|
+
`Resolve Async Node ${nodeCount} times`,
|
|
127
|
+
async () => {
|
|
128
|
+
// The test just resolves the last node and waits for player to complete.
|
|
129
|
+
resolveAsyncNode();
|
|
130
|
+
await playerCompletePromise;
|
|
131
|
+
},
|
|
132
|
+
{ iterations: 100, throws: true, setup },
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
});
|