dsh-perf-boost 0.2.2 → 0.2.3

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/CHANGELOG.md CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  ## 更新详情
6
6
 
7
+ ### 0.2.3
8
+
9
+ - 新增了「后台回收内存」的开关:窗口隐藏超过 45 秒后摘掉视频源释放缓冲、清空资源计时、停掉观察器;设置页有「立即回收」按钮,也显示当前 JS 堆占用的功能
7
10
  ### 0.2.2
8
11
 
9
12
  - 优化了长对话省渲染的实现,改成一处分样式接管子项,新消息进来自动生效的效果
package/README.md CHANGED
@@ -9,6 +9,10 @@ Client-side rendering optimizations for DSH Desktop.
9
9
 
10
10
  ## 更新详情
11
11
 
12
+ ### 0.2.3
13
+
14
+ - 新增了「后台回收内存」:窗口隐藏超过 45 秒后摘掉视频源释放缓冲、清空资源计时、停掉观察器;设置页可「立即回收」,并显示当前 JS 堆占用。
15
+
12
16
  ### 0.2.2
13
17
 
14
18
  - 优化了长对话省渲染的实现,改成一处分样式接管子项,新消息进来自动生效的效果
package/lib/client.js CHANGED
@@ -28,9 +28,16 @@ window.__ModuleLoader__.load({
28
28
  var STYLE_ID = 'dpb-style';
29
29
  var CV_CLASS = 'dpb-cv'; // 挂在滚动列表容器上,子项的 content-visibility 交给 CSS
30
30
  var CV_VAR = '--dpb-cis';
31
- var VERSION = '0.2.2';
31
+ var VERSION = '0.2.3';
32
32
  // 更新公告:只用「新增了…的功能 / 修复了…的问题 / 优化了…的效果」三种句式。
33
33
  var RELEASE_NOTES = [
34
+ {
35
+ version: '0.2.3',
36
+ items: [
37
+ '新增了后台回收内存的开关,窗口隐藏一会儿就把视频缓冲和资源记录放掉的功能',
38
+ '新增了设置页里显示当前 JS 堆占用的效果',
39
+ ],
40
+ },
34
41
  {
35
42
  version: '0.2.2',
36
43
  items: [
@@ -75,6 +82,7 @@ window.__ModuleLoader__.load({
75
82
  hiddenTimers: true,
76
83
  mediaPause: true,
77
84
  listGate: true,
85
+ bgTrim: true,
78
86
  // 默认关:会改观感或动画
79
87
  noBlur: false,
80
88
  reduceMotion: false,
@@ -258,6 +266,7 @@ window.__ModuleLoader__.load({
258
266
  timerMs: 0, timerRuns: 0, timerSkipped: 0,
259
267
  setMs: 0, setRuns: 0, setMerged: 0,
260
268
  lazyItems: 0, mediaPaused: 0, mediaLazy: 0,
269
+ trimRuns: 0, trimMedia: 0,
261
270
  };
262
271
  function metPer(x, n) { return n > 0 ? x / n : 0; }
263
272
  // rAF 那部分不算「省下」:页面隐藏时压住回调只是推迟,回到前台会一次性补跑,
@@ -1020,6 +1029,7 @@ window.__ModuleLoader__.load({
1020
1029
  MET.rafSkipped, MET.timerSkipped,
1021
1030
  g ? g.published : 0, g ? g.coalesced : 0,
1022
1031
  MET.lazyItems, MET.mediaLazy, MET.mediaPaused,
1032
+ MET.trimRuns, heapMb(),
1023
1033
  ].join('|');
1024
1034
  };
1025
1035
  var tick = function () {
@@ -1087,6 +1097,13 @@ window.__ModuleLoader__.load({
1087
1097
  warmupCall(v).then(function (real) { if (real !== null) setWarmupOn(real); });
1088
1098
  },
1089
1099
  })),
1100
+ React.createElement(Row, { label: '后台回收内存', hint: '窗口隐藏超过 45 秒后放掉视频缓冲、清空资源计时,观察器也停掉。可能会导致回到前台时视频要重新缓冲一下。默认开。' + lastTrimText() },
1101
+ React.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center', flex: '0 0 auto' } },
1102
+ React.createElement('button', {
1103
+ type: 'button', className: 'dpb-btn',
1104
+ onClick: function () { try { if (typeof window.__dpbTrim === 'function') window.__dpbTrim(); } catch (e) { void e; } bump(function (n) { return n + 1; }); },
1105
+ }, '立即回收'),
1106
+ React.createElement(Sw, { label: '后台回收内存', value: !!cfg.bgTrim, onChange: function (v) { setCfg({ bgTrim: v }); } }))),
1090
1107
  React.createElement(Row, { label: '关闭背景模糊', hint: '浮层从磨砂变纯色底,能看出来。默认关。' },
1091
1108
  React.createElement(Sw, { label: '关闭背景模糊', value: !!cfg.noBlur, onChange: function (v) { setCfg({ noBlur: v }); } })),
1092
1109
  React.createElement(Row, { label: '减少动画', hint: '关掉 CSS 动画和过渡,弹窗不再逐帧动。默认关。' },
@@ -1098,6 +1115,7 @@ window.__ModuleLoader__.load({
1098
1115
  React.createElement('div', { className: 'dpb-card' },
1099
1116
  React.createElement('div', { className: 'dpb-stat' },
1100
1117
  React.createElement('span', null, '版本 ', React.createElement('b', null, update.installed ? 'v' + update.installed : 'v' + VERSION)),
1118
+ React.createElement('span', null, '堆 ', React.createElement('b', null, heapMb() === null ? '—' : heapMb() + ' MB')),
1101
1119
  React.createElement('span', null, '最新 ', React.createElement('b', null,
1102
1120
  update.state === 'checking' ? '检查中…'
1103
1121
  : update.available ? 'v' + update.latest
@@ -1122,6 +1140,7 @@ window.__ModuleLoader__.load({
1122
1140
  else installRafThrottle();
1123
1141
  installTimerPause();
1124
1142
  applyStyle();
1143
+ onVisibilityForTrim();
1125
1144
  // 首屏别抢:等空闲再扫,扫描期间若在流式输出会往后推。
1126
1145
  idleRun(function () {
1127
1146
  try { applyLazyList(); } catch (e) { void e; }
@@ -1143,6 +1162,118 @@ window.__ModuleLoader__.load({
1143
1162
  else root.classList.remove('dpb-quiet');
1144
1163
  }
1145
1164
 
1165
+ // ————————————————— 后台回收内存 —————————————————
1166
+ // 隐藏超过 45 秒才动手:切走一下去看文件不动它,免得回来视频要重新缓冲。
1167
+ // 长期最小化时,把能放的全放掉:视频缓冲、资源计时、观察器、记录表。
1168
+ var BG_TRIM_AFTER_MS = 45000;
1169
+ var bgTrimTimer = 0;
1170
+
1171
+ function heapMb() {
1172
+ var m = null;
1173
+ try { m = performance.memory; } catch (e) { m = null; }
1174
+ if (!m || !m.usedJSHeapSize) return null;
1175
+ return Math.round(m.usedJSHeapSize / 1048576);
1176
+ }
1177
+
1178
+ function trimMedia() {
1179
+ var n = 0;
1180
+ var vids = document.querySelectorAll('video');
1181
+ for (var k = 0; k < vids.length; k++) {
1182
+ var v = vids[k];
1183
+ try {
1184
+ // 后台正在出声的不碰:用户可能在听。
1185
+ if (!v.paused && !v.muted && v.volume > 0) continue;
1186
+ if (v.getAttribute('data-dpb-src') !== null) continue;
1187
+ var src = v.getAttribute('src') || '';
1188
+ var kids = v.querySelectorAll('source');
1189
+ var sources = [];
1190
+ for (var j = 0; j < kids.length; j += 1) {
1191
+ sources.push({ src: kids[j].getAttribute('src') || '', type: kids[j].getAttribute('type') || '' });
1192
+ }
1193
+ v.setAttribute('data-dpb-src', src);
1194
+ v.setAttribute('data-dpb-pre', v.getAttribute('preload') || '');
1195
+ if (sources.length) v.setAttribute('data-dpb-sources', JSON.stringify(sources));
1196
+ v.setAttribute('preload', 'none');
1197
+ // 只把 src 摘掉再 load(),浏览器才真正丢弃已缓冲的媒体数据;
1198
+ // 留着 src 只是标记「别预载」,缓冲还在内存里(实测 buffered 不归零)。
1199
+ if (src || sources.length) {
1200
+ v.removeAttribute('src');
1201
+ for (var m = kids.length - 1; m >= 0; m -= 1) kids[m].remove();
1202
+ v.load();
1203
+ }
1204
+ n += 1;
1205
+ } catch (e) { void e; }
1206
+ }
1207
+ return n;
1208
+ }
1209
+
1210
+ function lastTrimText() {
1211
+ var t = window.__dpbLastTrim;
1212
+ if (!t) return '';
1213
+ var mins = Math.max(1, Math.round((Date.now() - t.at) / 60000));
1214
+ return ' 上次回收:' + mins + ' 分钟前,放掉 ' + t.freed + ' 个视频缓冲。';
1215
+ }
1216
+
1217
+ function trimMemory(why) {
1218
+ if (!cfg.bgTrim) return;
1219
+ var freed = 0;
1220
+ try { if (performance.clearResourceTimings) performance.clearResourceTimings(); } catch (e) { void e; }
1221
+ try { freed = trimMedia(); } catch (e) { void e; }
1222
+ try { if (mediaObserver) mediaObserver.disconnect(); } catch (e) { void e; }
1223
+ try { if (timerRecs.length > 200) timerRecs.splice(0, timerRecs.length - 200); } catch (e) { void e; }
1224
+ try { if (typeof window.gc === 'function') window.gc(); } catch (e) { void e; }
1225
+ MET.trimRuns += 1;
1226
+ MET.trimMedia += freed;
1227
+ try { window.__dpbLastTrim = { at: Date.now(), why: why, freed: freed, heap: heapMb() }; } catch (e) { void e; }
1228
+ }
1229
+
1230
+ // 设置页的「立即回收」与自检脚本都走这里。
1231
+ try { window.__dpbTrim = function () { trimMemory('manual'); return window.__dpbLastTrim || null; }; } catch (e) { void e; }
1232
+
1233
+ function restoreMediaPreload() {
1234
+ var list = document.querySelectorAll('[data-dpb-src]');
1235
+ for (var i = 0; i < list.length; i++) {
1236
+ try {
1237
+ var v = list[i];
1238
+ var src = v.getAttribute('data-dpb-src') || '';
1239
+ var pre = v.getAttribute('data-dpb-pre') || '';
1240
+ var srcs = null;
1241
+ try { srcs = JSON.parse(v.getAttribute('data-dpb-sources') || 'null'); } catch (e) { srcs = null; }
1242
+ if (src) v.setAttribute('src', src);
1243
+ if (srcs && srcs.length) {
1244
+ for (var j = 0; j < srcs.length; j += 1) {
1245
+ var el = document.createElement('source');
1246
+ if (srcs[j].src) el.setAttribute('src', srcs[j].src);
1247
+ if (srcs[j].type) el.setAttribute('type', srcs[j].type);
1248
+ v.appendChild(el);
1249
+ }
1250
+ }
1251
+ if (pre) v.setAttribute('preload', pre); else v.removeAttribute('preload');
1252
+ v.removeAttribute('data-dpb-src');
1253
+ v.removeAttribute('data-dpb-pre');
1254
+ v.removeAttribute('data-dpb-sources');
1255
+ // 把源接回去后重新 load 一次,浏览器才会重新按需取流。
1256
+ if (src || (srcs && srcs.length)) v.load();
1257
+ } catch (e) { void e; }
1258
+ }
1259
+ }
1260
+
1261
+ function onVisibilityForTrim() {
1262
+ if (bgTrimTimer) { window.clearTimeout(bgTrimTimer); bgTrimTimer = 0; }
1263
+ if (document.hidden) {
1264
+ if (!cfg.bgTrim) return;
1265
+ bgTrimTimer = window.setTimeout(function () {
1266
+ bgTrimTimer = 0;
1267
+ if (document.hidden) trimMemory('hidden');
1268
+ }, BG_TRIM_AFTER_MS);
1269
+ } else {
1270
+ try { restoreMediaPreload(); } catch (e) { void e; }
1271
+ idleRun(function () {
1272
+ try { applyViewportMedia(); } catch (e) { void e; }
1273
+ }, 300);
1274
+ }
1275
+ }
1276
+
1146
1277
  function mount() {
1147
1278
  applyAll();
1148
1279
  // 采样快照自己走:不依赖设置页开着,否则百分比只在打开设置后才更新。
@@ -1153,6 +1284,7 @@ window.__ModuleLoader__.load({
1153
1284
  }
1154
1285
  document.addEventListener('visibilitychange', flushTimers);
1155
1286
  document.addEventListener('visibilitychange', applyHiddenClass);
1287
+ document.addEventListener('visibilitychange', onVisibilityForTrim);
1156
1288
  applyHiddenClass();
1157
1289
  watchBusy();
1158
1290
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-perf-boost",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "DSH 桌面端性能优化(纯客户端):长对话省渲染、窗口隐藏不排帧默认开,关背景模糊/减少动画/空闲降帧按需打开,设置页显示实测省下的主线程时间。Client-side rendering optimizations for DeepSeek Harness Desktop.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",