Skip to content

perf: AppData.set() envia postMessage ao popup a cada mutação de estado em src/helpers/AppData.js #47

@NatanBudny

Description

@NatanBudny

Problema

Em src/helpers/AppData.js, toda chamada a set() envia imediatamente uma mensagem cross-window para o popup:

set(param, value) {
  store.commit("setData", [param, value]);

  const popup = this.get("popup");
  if (popup && !popup.closed) {
    popup.postMessage({ param, value }, window.location.origin);
  }
}

Durante a reprodução de áudio, o método timeUpdate em src/helpers/Media.js é disparado várias vezes por segundo pelo evento nativo do <audio> e chama $appdata.set() individualmente para cada propriedade:

  • modules.media.config.current_time
  • modules.media.config.duration
  • modules.media.config.progress
  • modules.media.config.slide_progress
  • modules.media.config.buffered
  • modules.media.config.slide_index

Com o popup aberto, isso gera 15–25 mensagens cross-window por segundo. Janelas diferentes rodam em processos separados no Chromium, tornando o postMessage entre elas uma operação de IPC (comunicação entre processos) — significativamente mais custosa do que comunicação dentro do mesmo processo.

Correção

Baterizar as mensagens usando requestAnimationFrame, acumulando todas as mutações do frame e enviando um único objeto ao popup:

// src/helpers/AppData.js
let pendingMessages = {};
let rafScheduled = false;

set(param, value) {
  store.commit("setData", [param, value]);

  const popup = this.get("popup");
  if (popup && !popup.closed && param !== "popup" && param !== "is_popup") {
    pendingMessages[param] = value;

    if (!rafScheduled) {
      rafScheduled = true;
      requestAnimationFrame(() => {
        popup.postMessage({ batch: pendingMessages }, window.location.origin);
        pendingMessages = {};
        rafScheduled = false;
      });
    }
  }
}

O receptor no popup (src/views/Popup.vue) precisaria ser atualizado para processar o formato batch:

window.addEventListener("message", (event) => {
  if (event.origin === window.location.origin) {
    if (event.data.batch) {
      Object.entries(event.data.batch).forEach(([param, value]) => {
        this.$appdata.set(param, value);
      });
    } else if (event.data.param) {
      this.$appdata.set(event.data.param, event.data.value);
    }
  }
});

Possíveis impactos

  • Redução de ~95% das mensagens cross-window durante playback
  • Ganho direto de fluidez no player e na janela popup simultânea
  • O popup passa a receber atualizações sincronizadas com o ciclo de renderização do navegador (60fps), em vez de receber rajadas de mensagens individuais
  • Sem perda de dados — todas as mutações do frame são incluídas no batch

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions