@netless/slide 1.4.56 → 1.4.58-alpha.0
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/README.md +12 -29
- package/lib/RenderingTaskManager.d.ts +9 -1
- package/lib/RenderingTaskManager.js +94 -4
- package/lib/Slide.d.ts +9 -0
- package/lib/Slide.js +36 -36
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -2,39 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## [示例及具体文档参考](https://github.com/netless-io/netless-slide-demo)
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
`@netless/slide` 默认按 FIFO 顺序执行所有接收到的同步事件。对于需要在弱网积压时优先追赶最新页面的 interactive 客户端,可以显式启用 `latest-pending-render`;可写端和只读端都可以使用:
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
const slide = new Slide({
|
|
11
|
-
// 其他配置
|
|
12
|
-
syncEventQueuePolicy: "latest-pending-render",
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
slide.setSyncEventQueuePolicy("fifo");
|
|
16
|
-
slide.setSyncEventQueuePolicy("latest-pending-render");
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
该策略只处理尚未开始执行的 pending 事件:
|
|
20
|
-
|
|
21
|
-
- 新的 `renderSlide` 到达时,删除同一资源段内排在它之前的 pending 翻页、`nextStep`、`prevStep`、交互动画和媒体操作。
|
|
22
|
-
- 保留最新 `renderSlide`,以及它之后到达的所有操作,并继续按 FIFO 执行。
|
|
23
|
-
- `setResource` 和未知事件是硬边界,不会被删除,也不会跨越边界压缩。
|
|
24
|
-
- 已经开始执行的事件不会被取消;该策略不保证完全不显示 running 中间页。
|
|
25
|
-
- 动态切换策略本身不会清空或重排已有队列;切换后新到达的 `renderSlide` 才会触发压缩。
|
|
26
|
-
- latest 策略下开始执行远端 `renderSlide`,或远端事件形成 pending 积压后,Slide 会暂时阻止本地 `nextStep()`、`prevStep()`、`renderSlide()`、`doRenderSlide()` 和画布交互;同步接收、状态恢复和队列执行不受影响。本机事件优先通过现有 Lock 的 UUID 回包识别,并以 `clientId` 作为补充,不会锁住正在操作的当前控制者。
|
|
27
|
-
- 临时输入锁在同步队列重新空闲后解除,并恢复调用方最近一次通过 `setInteractive()` 设置的权限;不会把原本的只读端恢复成可写。
|
|
28
|
-
|
|
29
|
-
该能力不会根据 `interactive` 自动开启。调用方应通过自己的灰度开关显式选择;关闭策略时可以恢复为 `fifo`,不会修改调用方原有的本地交互权限。
|
|
5
|
+
## changelog
|
|
30
6
|
|
|
31
|
-
|
|
7
|
+
### 1.4.58 (2026-09-07)
|
|
8
|
+
* 修复低版本 WebView 中纯色图形显示为黑块的问题
|
|
9
|
+
* 修复切页或销毁 Stage 后无限循环动画回调仍访问已释放 Pixi 对象导致的异常
|
|
10
|
+
* 完善渲染任务取消、失败后的清理与队列推进
|
|
32
11
|
|
|
33
|
-
|
|
12
|
+
### 1.4.57 (2026-08-27)
|
|
13
|
+
* 支持在客户端解码并播放本地 GIF 资源,兼容旧版 Safari
|
|
14
|
+
* 修复 WebGL 切页转场被错误关闭的问题
|
|
34
15
|
|
|
35
|
-
|
|
16
|
+
### 1.4.56 (2026-08-25)
|
|
17
|
+
* 修复冻结 (frozen) 恢复 (release) 时画面闪烁问题
|
|
18
|
+
* 完善 Canvas/WebGL 播放器销毁清理,避免状态切换后残留多个 canvas
|
|
36
19
|
|
|
37
|
-
###
|
|
20
|
+
### 1.4.55 (2026-08-21)
|
|
38
21
|
* 增加 `latest-pending-render` 同步队列策略,弱网积压时丢弃最后翻页前尚未执行的中间页面操作,并在追赶期间阻止本地输入
|
|
39
22
|
* 修复 PPT 图形内阴影(`innerShadow`)被错误渲染为不透明黑边的问题
|
|
40
23
|
* 按转换数据中的颜色、模糊半径、距离和方向渲染柔化内阴影
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import EventEmitter from "eventemitter3";
|
|
2
|
+
export declare class RenderTaskCancelledError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
constructor(message?: string);
|
|
5
|
+
}
|
|
2
6
|
export declare class Task {
|
|
3
7
|
state: "idle" | "start" | "end";
|
|
4
8
|
index: number;
|
|
@@ -6,16 +10,20 @@ export declare class Task {
|
|
|
6
10
|
private fn;
|
|
7
11
|
private eventHub;
|
|
8
12
|
id: string;
|
|
13
|
+
private cancelled;
|
|
9
14
|
constructor(index: number, slideIndex: number, fn: () => Promise<void>, eventHub: EventEmitter, id: string);
|
|
10
15
|
apply(): Promise<void>;
|
|
16
|
+
cancel(): void;
|
|
11
17
|
}
|
|
12
18
|
export declare class RenderingTaskManager {
|
|
13
19
|
eventHub: EventEmitter;
|
|
14
20
|
private tasks;
|
|
15
21
|
private index;
|
|
22
|
+
private destroyed;
|
|
16
23
|
constructor();
|
|
24
|
+
private cancelTask;
|
|
17
25
|
private replaceIdleTask;
|
|
18
|
-
addTask(fn: () => Promise<void>, slideIndex: number, id: string):
|
|
26
|
+
addTask(fn: () => Promise<void>, slideIndex: number, id: string): Task | undefined;
|
|
19
27
|
hasStartTask(): boolean;
|
|
20
28
|
destroy(): void;
|
|
21
29
|
}
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
if (typeof b !== "function" && b !== null)
|
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
+
extendStatics(d, b);
|
|
12
|
+
function __() { this.constructor = d; }
|
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
1
16
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
17
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
18
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -35,11 +50,24 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
35
50
|
}
|
|
36
51
|
};
|
|
37
52
|
import EventEmitter from "eventemitter3";
|
|
53
|
+
var RenderTaskCancelledError = /** @class */ (function (_super) {
|
|
54
|
+
__extends(RenderTaskCancelledError, _super);
|
|
55
|
+
function RenderTaskCancelledError(message) {
|
|
56
|
+
if (message === void 0) { message = "render task cancelled"; }
|
|
57
|
+
var _this = _super.call(this, message) || this;
|
|
58
|
+
_this.code = "RENDER_TASK_CANCELLED";
|
|
59
|
+
_this.name = "AbortError";
|
|
60
|
+
return _this;
|
|
61
|
+
}
|
|
62
|
+
return RenderTaskCancelledError;
|
|
63
|
+
}(Error));
|
|
64
|
+
export { RenderTaskCancelledError };
|
|
38
65
|
var Task = /** @class */ (function () {
|
|
39
66
|
function Task(index, slideIndex, fn, eventHub, id) {
|
|
40
67
|
this.state = "idle";
|
|
41
68
|
this.index = -1;
|
|
42
69
|
this.slideIndex = -1;
|
|
70
|
+
this.cancelled = false;
|
|
43
71
|
this.fn = fn;
|
|
44
72
|
this.index = index;
|
|
45
73
|
this.slideIndex = slideIndex;
|
|
@@ -52,6 +80,9 @@ var Task = /** @class */ (function () {
|
|
|
52
80
|
return __generator(this, function (_a) {
|
|
53
81
|
switch (_a.label) {
|
|
54
82
|
case 0:
|
|
83
|
+
if (this.cancelled) {
|
|
84
|
+
return [2 /*return*/];
|
|
85
|
+
}
|
|
55
86
|
this.eventHub.emit("task-start", this);
|
|
56
87
|
_a.label = 1;
|
|
57
88
|
case 1:
|
|
@@ -60,11 +91,25 @@ var Task = /** @class */ (function () {
|
|
|
60
91
|
return [4 /*yield*/, this.fn()];
|
|
61
92
|
case 2:
|
|
62
93
|
_a.sent();
|
|
94
|
+
if (this.cancelled) {
|
|
95
|
+
return [2 /*return*/];
|
|
96
|
+
}
|
|
63
97
|
this.state = "end";
|
|
64
98
|
this.eventHub.emit("task-end", this);
|
|
65
99
|
return [3 /*break*/, 4];
|
|
66
100
|
case 3:
|
|
67
101
|
e_1 = _a.sent();
|
|
102
|
+
if (this.cancelled) {
|
|
103
|
+
return [2 /*return*/];
|
|
104
|
+
}
|
|
105
|
+
if (e_1 instanceof RenderTaskCancelledError) {
|
|
106
|
+
this.cancel();
|
|
107
|
+
this.eventHub.emit("task-cancel", {
|
|
108
|
+
task: this,
|
|
109
|
+
error: e_1,
|
|
110
|
+
});
|
|
111
|
+
return [2 /*return*/];
|
|
112
|
+
}
|
|
68
113
|
this.eventHub.emit("task-error", {
|
|
69
114
|
task: this,
|
|
70
115
|
error: e_1,
|
|
@@ -75,6 +120,9 @@ var Task = /** @class */ (function () {
|
|
|
75
120
|
});
|
|
76
121
|
});
|
|
77
122
|
};
|
|
123
|
+
Task.prototype.cancel = function () {
|
|
124
|
+
this.cancelled = true;
|
|
125
|
+
};
|
|
78
126
|
return Task;
|
|
79
127
|
}());
|
|
80
128
|
export { Task };
|
|
@@ -84,6 +132,7 @@ var RenderingTaskManager = /** @class */ (function () {
|
|
|
84
132
|
this.eventHub = new EventEmitter();
|
|
85
133
|
this.tasks = [];
|
|
86
134
|
this.index = 0;
|
|
135
|
+
this.destroyed = false;
|
|
87
136
|
this.eventHub.on("task-end", function (task) {
|
|
88
137
|
var _a;
|
|
89
138
|
var selfIndex = _this.tasks.findIndex(function (t) { return t.index === task.index; });
|
|
@@ -98,15 +147,38 @@ var RenderingTaskManager = /** @class */ (function () {
|
|
|
98
147
|
_this.eventHub.emit("task-end-" + task.id);
|
|
99
148
|
});
|
|
100
149
|
this.eventHub.on("task-error", function (_a) {
|
|
101
|
-
var
|
|
150
|
+
var _b;
|
|
151
|
+
var task = _a.task, error = _a.error;
|
|
102
152
|
var selfIndex = _this.tasks.findIndex(function (t) { return t.index === task.index; });
|
|
153
|
+
var wasRunning = task.state === "start";
|
|
103
154
|
if (selfIndex >= 0) {
|
|
104
155
|
_this.tasks.splice(selfIndex, 1);
|
|
105
156
|
_this.replaceIdleTask();
|
|
157
|
+
if (wasRunning && !_this.destroyed) {
|
|
158
|
+
(_b = _this.tasks[selfIndex]) === null || _b === void 0 ? void 0 : _b.apply();
|
|
159
|
+
}
|
|
106
160
|
}
|
|
107
|
-
_this.eventHub.emit("task-error-" + task.id);
|
|
161
|
+
_this.eventHub.emit("task-error-" + task.id, error);
|
|
162
|
+
});
|
|
163
|
+
this.eventHub.on("task-cancel", function (_a) {
|
|
164
|
+
var _b;
|
|
165
|
+
var task = _a.task, error = _a.error;
|
|
166
|
+
var selfIndex = _this.tasks.findIndex(function (t) { return t.index === task.index; });
|
|
167
|
+
var wasRunning = task.state === "start";
|
|
168
|
+
if (selfIndex >= 0) {
|
|
169
|
+
_this.tasks.splice(selfIndex, 1);
|
|
170
|
+
if (wasRunning && !_this.destroyed) {
|
|
171
|
+
(_b = _this.tasks[selfIndex]) === null || _b === void 0 ? void 0 : _b.apply();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
_this.eventHub.emit("task-cancel-" + task.id, error);
|
|
108
175
|
});
|
|
109
176
|
}
|
|
177
|
+
RenderingTaskManager.prototype.cancelTask = function (task) {
|
|
178
|
+
var error = new RenderTaskCancelledError();
|
|
179
|
+
task.cancel();
|
|
180
|
+
this.eventHub.emit("task-cancel", { task: task, error: error });
|
|
181
|
+
};
|
|
110
182
|
RenderingTaskManager.prototype.replaceIdleTask = function () {
|
|
111
183
|
var _this = this;
|
|
112
184
|
var _a;
|
|
@@ -116,11 +188,19 @@ var RenderingTaskManager = /** @class */ (function () {
|
|
|
116
188
|
ids.add(i);
|
|
117
189
|
}
|
|
118
190
|
}
|
|
119
|
-
|
|
120
|
-
|
|
191
|
+
// Remove from the end so deleting one idle task does not shift the
|
|
192
|
+
// indexes selected for the remaining cancellations.
|
|
193
|
+
Array.from(ids).sort(function (a, b) { return b - a; }).forEach(function (id) {
|
|
194
|
+
var task = _this.tasks.splice(id, 1)[0];
|
|
195
|
+
if (task) {
|
|
196
|
+
_this.cancelTask(task);
|
|
197
|
+
}
|
|
121
198
|
});
|
|
122
199
|
};
|
|
123
200
|
RenderingTaskManager.prototype.addTask = function (fn, slideIndex, id) {
|
|
201
|
+
if (this.destroyed) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
124
204
|
var task = new Task(this.index++, slideIndex, fn, this.eventHub, id);
|
|
125
205
|
this.tasks.push(task);
|
|
126
206
|
this.tasks.sort(function (a, b) { return a.index - b.index; });
|
|
@@ -128,11 +208,21 @@ var RenderingTaskManager = /** @class */ (function () {
|
|
|
128
208
|
if (this.tasks.length === 1) {
|
|
129
209
|
task.apply();
|
|
130
210
|
}
|
|
211
|
+
return task;
|
|
131
212
|
};
|
|
132
213
|
RenderingTaskManager.prototype.hasStartTask = function () {
|
|
133
214
|
return this.tasks.some(function (t) { return t.state === "start"; });
|
|
134
215
|
};
|
|
135
216
|
RenderingTaskManager.prototype.destroy = function () {
|
|
217
|
+
var _this = this;
|
|
218
|
+
if (this.destroyed) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
this.destroyed = true;
|
|
222
|
+
var tasks = this.tasks.splice(0);
|
|
223
|
+
tasks.forEach(function (task) {
|
|
224
|
+
_this.cancelTask(task);
|
|
225
|
+
});
|
|
136
226
|
this.eventHub.removeAllListeners();
|
|
137
227
|
};
|
|
138
228
|
return RenderingTaskManager;
|
package/lib/Slide.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { AliTrackLogger } from "./AliTrackLogger";
|
|
|
5
5
|
import { preloadResource } from "./global";
|
|
6
6
|
export { ErrorType, PreloadCancelledError } from "@netless/ppt-player";
|
|
7
7
|
export type { SyncEventQueuePolicy } from "./SyncTaskManager";
|
|
8
|
+
export declare const LOCAL_GIF_RUNTIME_CAPABILITY = "netless-slide-local-gif-production-client-geometry";
|
|
8
9
|
export declare type UrlInterrupter = (url: string) => Promise<string>;
|
|
9
10
|
export interface ILoaderDelegate {
|
|
10
11
|
/**
|
|
@@ -179,6 +180,10 @@ export interface ISlideRenderOptions {
|
|
|
179
180
|
*/
|
|
180
181
|
transitionResolutionLevel?: number;
|
|
181
182
|
antialias?: boolean;
|
|
183
|
+
/** Maximum compressed bytes accepted for one client-decoded GIF. */
|
|
184
|
+
localGifMaxCompressedBytes?: number;
|
|
185
|
+
/** Maximum estimated GIF working set for one cached slide. */
|
|
186
|
+
localGifMaxWorkingSetBytes?: number;
|
|
182
187
|
}
|
|
183
188
|
export interface INavigatorDelegate {
|
|
184
189
|
gotoPage?: (index: number) => void;
|
|
@@ -451,6 +456,9 @@ export declare class Slide extends Slide_base {
|
|
|
451
456
|
private resize;
|
|
452
457
|
private isAnimating;
|
|
453
458
|
private renderingTaskManager;
|
|
459
|
+
private lifecycle;
|
|
460
|
+
private lifecycleGeneration;
|
|
461
|
+
private renderVisibilityTimers;
|
|
454
462
|
private isLoading;
|
|
455
463
|
private isReleasing;
|
|
456
464
|
private interactive;
|
|
@@ -498,6 +506,7 @@ export declare class Slide extends Slide_base {
|
|
|
498
506
|
private handleSyncQueueCompactRenderComplete;
|
|
499
507
|
private handleSyncQueueCatchUpStateChange;
|
|
500
508
|
private updatePlayerInteractive;
|
|
509
|
+
private observeRenderTask;
|
|
501
510
|
private recoverHandler;
|
|
502
511
|
private reportError;
|
|
503
512
|
initSlideConfig(config: ISlideConfig): ISlideConfig;
|