c165f2f788
Agrega 19 issues técnicas documentando funcionalidades implementadas y pendientes. Issues completadas (movidas a dev/issues/completed/): - 001-conversor-web-markdown.md - 002-accessibility-tree.md - 003-gestion-cookies-perfil.md - 004-gestion-extensiones-chrome.md - 005-eliminar-timeouts-innecesarios.md Issues implementadas: - 006-manejo-tabs-ventanas.md - 016-manejo-iframes.md - 017-actions-api.md - 018-file-uploads.md - 019-expected-conditions-mejoradas.md Issues pendientes (media prioridad): - 007-alert-prompt-confirm-handling.md - 008-screenshot-elementos-especificos.md - 009-pdf-generation.md - 010-device-emulation-completo.md - 011-downloads-handling.md Issues pendientes (baja prioridad / avanzado): - 012-browser-contexts-multi-sesion.md - 013-video-recording.md - 014-network-mocking-avanzado.md - 015-geolocation-permissions.md Incluye también dev/NUEVAS_FUNCIONALIDADES.md con resumen completo. Directorio: dev/
4.5 KiB
4.5 KiB
Issue #005: Eliminar timeouts innecesarios del código
Tipo: Improvement Prioridad: Alta Estado: Pendiente
Descripción
Eliminar todos los time.Sleep() y timeouts hardcodeados innecesarios del código, reemplazándolos con esperas basadas en eventos CDP cuando sea posible.
Problema actual
El código tiene múltiples time.Sleep() arbitrarios:
time.Sleep(2 * time.Second)en examples/basic.gotime.Sleep(3 * time.Second)en cmd/list_blog.go- Timeouts hardcodeados en navegación
Estos timeouts son problemáticos porque:
- No se adaptan a velocidad real de carga
- Desperdicían tiempo en conexiones rápidas
- Fallan en conexiones lentas
- Hacen el código menos robusto
Estrategia de reemplazo
1. Eventos CDP de carga de página
En lugar de:
b.Navigate(ctx, url, nil)
time.Sleep(3 * time.Second)
Usar eventos CDP:
opts := browser.DefaultNavigateOptions()
opts.WaitUntil = "networkidle" // o "load" o "domcontentloaded"
b.Navigate(ctx, url, opts)
// No sleep necesario, Navigate espera el evento
2. Esperar por selectores
En lugar de:
time.Sleep(2 * time.Second)
html, _ := b.GetHTML(ctx, ".content")
Usar:
b.WaitForSelector(ctx, ".content", 30*time.Second)
html, _ := b.GetHTML(ctx, ".content")
3. Esperar por condiciones JavaScript
En lugar de:
time.Sleep(1 * time.Second)
result, _ := b.Evaluate(ctx, "window.dataReady")
Usar:
b.WaitForFunction(ctx, "window.dataReady === true", 100*time.Millisecond)
result, _ := b.Evaluate(ctx, "window.data")
4. Eventos de red
Esperar que network esté idle:
// Implementar WaitForNetworkIdle()
b.WaitForNetworkIdle(ctx, 500*time.Millisecond, 30*time.Second)
Eventos CDP útiles
Page domain
Page.loadEventFired- Página cargada completamentePage.domContentEventFired- DOM listoPage.frameStoppedLoading- Frame dejó de cargar
Network domain
Network.requestWillBeSent- Request iniciadoNetwork.responseReceived- Response recibidaNetwork.loadingFinished- Recurso terminó de cargarNetwork.loadingFailed- Recurso falló
Métodos a implementar
// WaitForEvent espera un evento CDP específico
func (b *Browser) WaitForEvent(ctx context.Context, eventName string, timeout time.Duration) error
// WaitForNetworkIdle espera que no haya requests de red por X tiempo
func (b *Browser) WaitForNetworkIdle(ctx context.Context, idleTime, timeout time.Duration) error
// WaitForFunction espera que una función JS retorne true
func (b *Browser) WaitForFunction(ctx context.Context, fn string, checkInterval time.Duration) error
// WaitForNavigation espera que navegación complete
func (b *Browser) WaitForNavigation(ctx context.Context, timeout time.Duration) error
Archivos a revisar y actualizar
examples/basic.go- Eliminar time.Sleepexamples/advanced.go- Reemplazar con esperas basadas en eventoscmd/list_blog.go- Usar WaitForSelectorpkg/browser/navigation.go- Mejorar Navigate() para esperar eventospkg/browser/browser.go- Agregar métodos de espera
Implementación en Navigate()
func (b *Browser) Navigate(ctx context.Context, url string, opts *NavigateOptions) error {
if opts == nil {
opts = DefaultNavigateOptions()
}
// Registrar listener ANTES de navegar
loadedChan := make(chan struct{})
b.client.On("Page.loadEventFired", func() {
close(loadedChan)
})
// Enviar comando de navegación
_, err := b.client.SendCommand(ctx, "Page.navigate", map[string]interface{}{
"url": url,
})
if err != nil {
return err
}
// Esperar evento según opts.WaitUntil
select {
case <-loadedChan:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
Beneficios
✅ Más rápido: No espera más de lo necesario ✅ Más robusto: Falla con timeout claro, no con misterioso "elemento no encontrado" ✅ Más confiable: Se adapta a velocidad real de página ✅ Mejor UX: Feedback claro de qué se está esperando
Testing
Probar con:
- Conexiones rápidas (localhost)
- Conexiones lentas (throttling)
- Páginas con mucho JavaScript
- Páginas con assets pesados
- SPAs (React, Vue) que cargan async
Referencias
- CDP Page events: https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-loadEventFired
- CDP Network events: https://chromedevtools.github.io/devtools-protocol/tot/Network/
- Puppeteer waitFor: https://pptr.dev/guides/page-interactions#waiting