Asyncify e JSPI: troca de pilha no PHP WebAssembly
O Asyncify permite que código C ou C++ síncrono interaja com JavaScript assíncrono. Tecnicamente, ele salva toda a pilha de chamadas C antes de devolver o controle ao JavaScript e, em seguida, a restaura quando a chamada assíncrona termina. Isso é chamado de troca de pilha.
O suporte a rede na build WebAssembly do PHP é implementado com Asyncify. Quando o PHP faz uma requisição de rede, ele devolve o controle ao JavaScript, que executa a requisição e retoma o PHP quando a resposta está pronta. Funciona bem o suficiente para que a build PHP possa chamar APIs web, instalar pacotes do Composer e até conectar a um servidor MySQL.
Falhas do Asyncify
A troca de pilha exige envolver todas as funções C que possam estar na pilha de chamadas no momento de uma chamada assíncrona. Envolver indiscriminadamente cada função C adiciona uma sobrecarga significativa, por isso mantemos uma lista de nomes de funções específicas:
Infelizmente, omitir um único item dessa lista resulta em falha do WebAssembly sempre que essa função faz parte da pilha de chamadas quando uma chamada assíncrona é feita. O erro se parece com isto:

O Asyncify pode listar automaticamente todas as funções C necessárias quando compilado sem ASYNCIFY_ONLY, mas essa detecção automática é excessiva e acaba listando cerca de 70.000 funções C, o que aumenta o tempo de inicialização para 4,5 s. Por isso mantemos a lista manualmente.
Se quiser mais detalhes, veja a issue 251 no GitHub.
Corrigindo falhas do Asyncify
O Pull Request 253 adiciona um comando fix-asyncify que executa uma suíte de testes especializada e adiciona automaticamente à lista ASYNCIFY_ONLY quaisquer funções C em falta identificadas.
Se você encontrar uma falha como a acima, pode corrigi-la assim:
- Identificar um caminho de código PHP que dispara a falha — o rastreamento de pilha no terminal deve ajudar.
- Adicionar um caso de teste que dispara a falha em
packages/php-wasm/node/src/test/php-asyncify.spec.ts - Executar:
npm run fix-asyncify - Fazer commit do caso de teste, do Dockerfile atualizado e do PHP.wasm reconstruído
JSPI: a alternativa moderna ao Asyncify
A API JavaScript Promise Integration (JSPI) trata a troca de pilha nativamente no V8, eliminando a necessidade do envolvimento de funções do Asyncify. O WordPress Playground agora distribui builds JSPI junto com builds Asyncify para todas as versões do PHP (7.4–8.5).
Estado atual:
- O Playground CLI detecta suporte a JSPI automaticamente e o ativa — sem flags manuais
- Node.js 23+ oferece JSPI nativamente; Node.js 22 exige a flag
--experimental-wasm-jspi(tratada automaticamente pelo CLI) - Espera-se que Node.js 24+ tenha JSPI sem flag
- O suporte nos navegadores varia: o JSPI está disponível no Chrome e em navegadores baseados em Chromium atrás de flags
Otimização do tamanho do binário com MAIN_MODULE=2
As builds Asyncify e JSPI são compiladas com a flag MAIN_MODULE=2 do Emscripten, que elimina código morto nos símbolos exportados. Apenas os símbolos de que as extensões dinâmicas realmente precisam são exportados.
Impacto:
- Tamanho total dos binários reduzido em 122 MB (13,7%)
- Arquivos
.wasmreduzidos em 109 MB (16%) - Código cola JavaScript reduzido em 14,5 MB (63%)
Essa otimização vale para todas as versões do PHP (7.4–8.5) nos alvos Node.js e Web. A lista de símbolos exportados é gerenciada centralmente no Dockerfile, com exportações condicionais para extensões específicas (por exemplo, __c_longjmp para Xdebug, _wasm_recv para Memcached).