|
10 | 10 | const MUTATION_BURST_THRESHOLD = 150 |
11 | 11 | const MUTATION_COOLDOWN_MS = 5000 |
12 | 12 | const MUTATION_FLUSH_DELAY = 200 |
| 13 | + const MUTATION_OBSERVER_LIFETIME_MS = 30000 |
13 | 14 | const CONTEXT_INVALIDATED_PATTERN = /extension context invalidated|context invalidated/i |
14 | 15 | const OBSERVER_INSTANCE_KEY = '__stackPrismContentObserver__' |
15 | 16 | const SKIP_TAGS = new Set(['VIDEO', 'AUDIO', 'CANVAS', 'PICTURE', 'SOURCE', 'TRACK', 'SVG', 'IMG']) |
|
51 | 52 | let mutationBurstWindowStart = Date.now() |
52 | 53 | let mutationBurstCount = 0 |
53 | 54 | let mutationCooldownUntil = 0 |
| 55 | + let mutationCooldownReconnect = 0 |
| 56 | + let mutationLifetimeTimer = 0 |
54 | 57 |
|
55 | 58 | // ----- 调试埋点(默认关闭,开启:localStorage.setItem('__sp_observer_debug__','1') + 刷新) ----- |
56 | 59 |
|
|
380 | 383 | state.url = location.href |
381 | 384 | state.title = document.title |
382 | 385 | collectStaticSnapshot() |
| 386 | + try { |
| 387 | + if (document.body) collectFromElement(document.body) |
| 388 | + } catch { |
| 389 | + // ignore |
| 390 | + } |
383 | 391 | addDomMarker(`route:${location.pathname}${location.search}`) |
384 | 392 | scheduleSend() |
385 | 393 | } |
|
411 | 419 | pendingMutationFrame = 0 |
412 | 420 | } |
413 | 421 | pendingMutationNodes = [] |
| 422 | + if (mutationCooldownReconnect) { |
| 423 | + window.clearTimeout(mutationCooldownReconnect) |
| 424 | + mutationCooldownReconnect = 0 |
| 425 | + } |
| 426 | + if (mutationLifetimeTimer) { |
| 427 | + window.clearTimeout(mutationLifetimeTimer) |
| 428 | + mutationLifetimeTimer = 0 |
| 429 | + } |
414 | 430 | if (perfDumpTimer) { |
415 | 431 | window.clearInterval(perfDumpTimer) |
416 | 432 | perfDumpTimer = 0 |
|
518 | 534 | pendingMutationFrame = setTimeout(processPendingMutationNodes, MUTATION_FLUSH_DELAY) |
519 | 535 | } |
520 | 536 |
|
| 537 | + const observeMutationTarget = () => { |
| 538 | + if (!mutationObserver) return |
| 539 | + const target = document.body || document.documentElement || document |
| 540 | + try { |
| 541 | + mutationObserver.observe(target, { childList: true, subtree: true }) |
| 542 | + } catch { |
| 543 | + // ignore |
| 544 | + } |
| 545 | + } |
| 546 | + |
521 | 547 | const triggerMutationCooldown = now => { |
522 | 548 | mutationCooldownUntil = now + MUTATION_COOLDOWN_MS |
523 | 549 | pendingMutationNodes = [] |
524 | 550 | if (pendingMutationFrame) { |
525 | 551 | clearTimeout(pendingMutationFrame) |
526 | 552 | pendingMutationFrame = 0 |
527 | 553 | } |
| 554 | + if (mutationObserver) { |
| 555 | + mutationObserver.disconnect() |
| 556 | + if (mutationCooldownReconnect) { |
| 557 | + window.clearTimeout(mutationCooldownReconnect) |
| 558 | + } |
| 559 | + mutationCooldownReconnect = window.setTimeout(() => { |
| 560 | + mutationCooldownReconnect = 0 |
| 561 | + if (stopped) return |
| 562 | + observeMutationTarget() |
| 563 | + }, MUTATION_COOLDOWN_MS) |
| 564 | + } |
528 | 565 | } |
529 | 566 |
|
530 | 567 | const installMutationObserver = () => { |
531 | | - const root = document.documentElement || document |
532 | 568 | const observer = new MutationObserver(mutations => { |
533 | 569 | if (stopped) return |
534 | 570 | const now = Date.now() |
|
573 | 609 | perfMeasure('sp:mutation-callback', 'sp:mo-start', { mutations: mutations.length, accepted, cooldown: false }) |
574 | 610 | }) |
575 | 611 | mutationObserver = observer |
576 | | - observer.observe(root, { childList: true, subtree: true }) |
| 612 | + observeMutationTarget() |
577 | 613 | } |
578 | 614 |
|
579 | 615 | const installNavigationObserver = () => { |
|
618 | 654 | installMutationObserver() |
619 | 655 | installNavigationObserver() |
620 | 656 | scheduleSend() |
| 657 | + mutationLifetimeTimer = window.setTimeout(() => { |
| 658 | + mutationLifetimeTimer = 0 |
| 659 | + if (stopped) return |
| 660 | + if (mutationCooldownReconnect) { |
| 661 | + window.clearTimeout(mutationCooldownReconnect) |
| 662 | + mutationCooldownReconnect = 0 |
| 663 | + } |
| 664 | + if (mutationObserver) { |
| 665 | + mutationObserver.disconnect() |
| 666 | + mutationObserver = null |
| 667 | + } |
| 668 | + }, MUTATION_OBSERVER_LIFETIME_MS) |
621 | 669 | if (PERF_DEBUG) { |
622 | 670 | console.log('[StackPrism observer] 性能埋点已启用,每 ' + PERF_DUMP_INTERVAL_MS + 'ms 输出一次摘要') |
623 | 671 | perfDumpTimer = window.setInterval(dumpPerfSnapshot, PERF_DUMP_INTERVAL_MS) |
|
0 commit comments