@netless/slide 1.4.55-alpha.0 → 1.4.55-alpha.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.
@@ -1,11 +1,51 @@
1
- import { SyncEvent } from "./Slide";
1
+ import type { SyncEvent } from "./Slide";
2
+ export declare type SyncEventQueuePolicy = "fifo" | "latest-pending-render";
3
+ export declare type SyncEventQueueMode = "interactive" | "sync" | "local" | "addLink";
4
+ export interface SyncTaskCompactInfo {
5
+ policy: "latest-pending-render";
6
+ droppedEventCount: number;
7
+ droppedRenderCount: number;
8
+ droppedStepCount: number;
9
+ droppedAnimationCount: number;
10
+ droppedMediaCount: number;
11
+ droppedOperationCount: number;
12
+ droppedEventTypes: {
13
+ [eventType: string]: number;
14
+ };
15
+ retainedSlideIndex: number;
16
+ retainedRenderReceivedAt: number;
17
+ hasRunningTask: boolean;
18
+ hardBoundaryType?: string;
19
+ }
20
+ export interface SyncTaskManagerOptions {
21
+ policy?: SyncEventQueuePolicy;
22
+ onCompact?: (info: SyncTaskCompactInfo) => void;
23
+ onCompactedRenderComplete?: (info: SyncTaskCompactInfo, renderEndAt: number) => void;
24
+ onCatchUpStateChange?: (isCatchingUp: boolean) => void;
25
+ shouldTrackCatchUpEvent?: (event: SyncEvent) => boolean;
26
+ }
27
+ export declare function resolveSyncEventQueuePolicy(mode: SyncEventQueueMode, policy?: SyncEventQueuePolicy): SyncEventQueuePolicy;
2
28
  export declare class SyncTaskManager {
3
29
  private fn;
4
30
  private tasks;
5
31
  private isDestroy;
6
32
  private isScheduling;
7
- constructor(fn: (arg: SyncEvent) => Promise<void>);
33
+ private isTaskRunning;
34
+ private isCatchingUp;
35
+ private runningTask?;
36
+ private policy;
37
+ private onCompact?;
38
+ private onCompactedRenderComplete?;
39
+ private onCatchUpStateChange?;
40
+ private shouldTrackCatchUpEvent?;
41
+ private compactedTasks;
42
+ constructor(fn: (arg: SyncEvent) => Promise<void>, options?: SyncTaskManagerOptions);
8
43
  destroy(): void;
44
+ setPolicy(policy: SyncEventQueuePolicy): void;
45
+ private setCatchUpState;
46
+ private isCatchUpEvent;
47
+ private finishTask;
9
48
  private schedule;
10
- addTask(evt: SyncEvent): void;
49
+ private compactForRender;
50
+ addTask(event: SyncEvent): SyncTaskCompactInfo | undefined;
11
51
  }
@@ -1,33 +1,205 @@
1
+ function assertSyncEventQueuePolicy(policy) {
2
+ if (policy !== "fifo" && policy !== "latest-pending-render") {
3
+ throw new Error("Invalid sync event queue policy: " + policy);
4
+ }
5
+ }
6
+ export function resolveSyncEventQueuePolicy(mode, policy) {
7
+ if (policy === void 0) { policy = "fifo"; }
8
+ assertSyncEventQueuePolicy(policy);
9
+ return mode === "interactive" ? policy : "fifo";
10
+ }
11
+ function isPageScopedEvent(event) {
12
+ switch (event.type) {
13
+ case "renderSlide":
14
+ case "nextStep":
15
+ case "prevStep":
16
+ case "interactiveAnim":
17
+ case "mediaPlay":
18
+ case "mediaPause":
19
+ case "mediaSeek":
20
+ case "mediaFullscreen":
21
+ return true;
22
+ default:
23
+ return false;
24
+ }
25
+ }
1
26
  var SyncTaskManager = /** @class */ (function () {
2
- function SyncTaskManager(fn) {
27
+ function SyncTaskManager(fn, options) {
3
28
  var _this = this;
29
+ if (options === void 0) { options = {}; }
4
30
  this.tasks = [];
5
31
  this.isDestroy = false;
6
32
  this.isScheduling = false;
33
+ this.isTaskRunning = false;
34
+ this.isCatchingUp = false;
35
+ this.compactedTasks = new WeakMap();
36
+ this.finishTask = function () {
37
+ _this.isTaskRunning = false;
38
+ _this.runningTask = undefined;
39
+ if (_this.isDestroy) {
40
+ _this.tasks.length = 0;
41
+ _this.isScheduling = false;
42
+ }
43
+ else if (_this.tasks.length > 0) {
44
+ window.requestAnimationFrame(_this.schedule);
45
+ }
46
+ else {
47
+ _this.isScheduling = false;
48
+ _this.setCatchUpState(false);
49
+ }
50
+ };
7
51
  this.schedule = function () {
52
+ if (_this.isDestroy) {
53
+ _this.tasks.length = 0;
54
+ _this.isScheduling = false;
55
+ return;
56
+ }
8
57
  _this.isScheduling = true;
9
58
  var task = _this.tasks.shift();
10
- if (task && !_this.isDestroy) {
11
- _this.fn(task).finally(function () {
12
- if (_this.tasks.length > 0) {
13
- window.requestAnimationFrame(_this.schedule);
14
- }
15
- else {
16
- _this.isScheduling = false;
59
+ if (!task) {
60
+ _this.isScheduling = false;
61
+ return;
62
+ }
63
+ _this.isTaskRunning = true;
64
+ _this.runningTask = task;
65
+ var compactInfo = _this.compactedTasks.get(task);
66
+ try {
67
+ _this.fn(task).then(function () {
68
+ var _a;
69
+ _this.compactedTasks.delete(task);
70
+ if (compactInfo && !_this.isDestroy) {
71
+ try {
72
+ (_a = _this.onCompactedRenderComplete) === null || _a === void 0 ? void 0 : _a.call(_this, compactInfo, Date.now());
73
+ }
74
+ catch ( /* Observability must not interrupt synchronization. */_b) { /* Observability must not interrupt synchronization. */ }
17
75
  }
76
+ _this.finishTask();
77
+ }, function () {
78
+ _this.compactedTasks.delete(task);
79
+ _this.finishTask();
18
80
  });
19
81
  }
82
+ catch (_a) {
83
+ _this.compactedTasks.delete(task);
84
+ _this.finishTask();
85
+ }
20
86
  };
21
87
  this.fn = fn;
88
+ this.policy = options.policy || "fifo";
89
+ this.onCompact = options.onCompact;
90
+ this.onCompactedRenderComplete = options.onCompactedRenderComplete;
91
+ this.onCatchUpStateChange = options.onCatchUpStateChange;
92
+ this.shouldTrackCatchUpEvent = options.shouldTrackCatchUpEvent;
93
+ assertSyncEventQueuePolicy(this.policy);
22
94
  }
23
95
  SyncTaskManager.prototype.destroy = function () {
24
96
  this.isDestroy = true;
97
+ this.isCatchingUp = false;
98
+ this.runningTask = undefined;
99
+ this.tasks.length = 0;
100
+ };
101
+ SyncTaskManager.prototype.setPolicy = function (policy) {
102
+ assertSyncEventQueuePolicy(policy);
103
+ this.policy = policy;
104
+ };
105
+ SyncTaskManager.prototype.setCatchUpState = function (isCatchingUp) {
106
+ var _a;
107
+ if (this.isCatchingUp === isCatchingUp) {
108
+ return;
109
+ }
110
+ this.isCatchingUp = isCatchingUp;
111
+ try {
112
+ (_a = this.onCatchUpStateChange) === null || _a === void 0 ? void 0 : _a.call(this, isCatchingUp);
113
+ }
114
+ catch ( /* Observability must not interrupt synchronization. */_b) { /* Observability must not interrupt synchronization. */ }
25
115
  };
26
- SyncTaskManager.prototype.addTask = function (evt) {
27
- this.tasks.push(evt);
116
+ SyncTaskManager.prototype.isCatchUpEvent = function (event) {
117
+ var _a, _b;
118
+ try {
119
+ return (_b = (_a = this.shouldTrackCatchUpEvent) === null || _a === void 0 ? void 0 : _a.call(this, event)) !== null && _b !== void 0 ? _b : true;
120
+ }
121
+ catch (_c) {
122
+ return true;
123
+ }
124
+ };
125
+ SyncTaskManager.prototype.compactForRender = function (event) {
126
+ var droppedEventTypes = {};
127
+ var droppedEventCount = 0;
128
+ var droppedRenderCount = 0;
129
+ var droppedStepCount = 0;
130
+ var droppedAnimationCount = 0;
131
+ var droppedMediaCount = 0;
132
+ while (this.tasks.length > 0) {
133
+ var pendingEvent = this.tasks[this.tasks.length - 1];
134
+ if (!isPageScopedEvent(pendingEvent)) {
135
+ break;
136
+ }
137
+ this.tasks.pop();
138
+ this.compactedTasks.delete(pendingEvent);
139
+ droppedEventCount += 1;
140
+ droppedEventTypes[pendingEvent.type] = (droppedEventTypes[pendingEvent.type] || 0) + 1;
141
+ if (pendingEvent.type === "renderSlide") {
142
+ droppedRenderCount += 1;
143
+ }
144
+ else if (pendingEvent.type === "nextStep" || pendingEvent.type === "prevStep") {
145
+ droppedStepCount += 1;
146
+ }
147
+ else if (pendingEvent.type === "interactiveAnim") {
148
+ droppedAnimationCount += 1;
149
+ }
150
+ else {
151
+ droppedMediaCount += 1;
152
+ }
153
+ }
154
+ if (droppedEventCount === 0) {
155
+ return undefined;
156
+ }
157
+ var boundaryEvent = this.tasks[this.tasks.length - 1];
158
+ return {
159
+ policy: "latest-pending-render",
160
+ droppedEventCount: droppedEventCount,
161
+ droppedRenderCount: droppedRenderCount,
162
+ droppedStepCount: droppedStepCount,
163
+ droppedAnimationCount: droppedAnimationCount,
164
+ droppedMediaCount: droppedMediaCount,
165
+ droppedOperationCount: droppedEventCount - droppedRenderCount,
166
+ droppedEventTypes: droppedEventTypes,
167
+ retainedSlideIndex: event.index,
168
+ retainedRenderReceivedAt: Date.now(),
169
+ hasRunningTask: this.isTaskRunning,
170
+ hardBoundaryType: boundaryEvent === null || boundaryEvent === void 0 ? void 0 : boundaryEvent.type,
171
+ };
172
+ };
173
+ SyncTaskManager.prototype.addTask = function (event) {
174
+ var _this = this;
175
+ var _a;
176
+ if (this.isDestroy) {
177
+ return undefined;
178
+ }
179
+ var hasPendingWork = this.isTaskRunning || this.tasks.length > 0;
180
+ var isIncomingCatchUpEvent = this.policy === "latest-pending-render" && this.isCatchUpEvent(event);
181
+ var hasCatchUpEvent = this.policy === "latest-pending-render" && (isIncomingCatchUpEvent ||
182
+ (!!this.runningTask && this.isCatchUpEvent(this.runningTask)) ||
183
+ this.tasks.some(function (pendingEvent) { return _this.isCatchUpEvent(pendingEvent); }));
184
+ var compactInfo = this.policy === "latest-pending-render" && event.type === "renderSlide" ?
185
+ this.compactForRender(event) :
186
+ undefined;
187
+ this.tasks.push(event);
188
+ var shouldStartCatchUp = hasCatchUpEvent && (hasPendingWork || (isIncomingCatchUpEvent && event.type === "renderSlide"));
189
+ if (shouldStartCatchUp) {
190
+ this.setCatchUpState(true);
191
+ }
192
+ if (compactInfo) {
193
+ this.compactedTasks.set(event, compactInfo);
194
+ try {
195
+ (_a = this.onCompact) === null || _a === void 0 ? void 0 : _a.call(this, compactInfo);
196
+ }
197
+ catch ( /* Observability must not interrupt synchronization. */_b) { /* Observability must not interrupt synchronization. */ }
198
+ }
28
199
  if (!this.isScheduling) {
29
200
  this.schedule();
30
201
  }
202
+ return compactInfo;
31
203
  };
32
204
  return SyncTaskManager;
33
205
  }());
package/lib/global.js CHANGED
@@ -57,7 +57,7 @@ export function preloadResource(taskId, prefix, maxResolutionLevel, onProgress,
57
57
  maxFPS: 1,
58
58
  resolution: 1,
59
59
  maxResolutionLevel: maxResolutionLevel,
60
- forceCanvas: false,
60
+ forceCanvas: true,
61
61
  },
62
62
  mode: "local",
63
63
  interactive: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/slide",
3
- "version": "1.4.55-alpha.0",
3
+ "version": "1.4.55-alpha.2",
4
4
  "description": "> TODO: description",
5
5
  "author": "huaguzheng <huaguzheng2007@126.com>",
6
6
  "homepage": "https://github.com/netless-io/netless-slide-demo",
@@ -16,7 +16,7 @@
16
16
  ],
17
17
  "scripts": {
18
18
  "dev": "tsc",
19
- "test": "jest",
19
+ "test": "node __tests__/SyncTaskManager.test.js",
20
20
  "build": "webpack --config webpack.config.js",
21
21
  "watch": "webpack --config webpack.config.js --watch"
22
22
  },
@@ -31,7 +31,8 @@
31
31
  "devDependencies": {
32
32
  "@types/dat.gui": "^0.7.7",
33
33
  "glsl-shader-loader": "^0.1.6",
34
- "ts-loader": "8.3.0"
34
+ "ts-loader": "8.3.0",
35
+ "typescript": "4.4.4"
35
36
  },
36
37
  "publishConfig": {
37
38
  "access": "public"