Perdón por la probable pregunta trivial, pero sigo sin entender cómo funcionan las transmisiones en node.js.
Quiero analizar un archivo html y obtener la ruta del primer script que encuentro. Me gustaría interrumpir el análisis después de la primera coincidencia, pero el oyente onopentag() todavía se invoca hasta el final efectivo del archivo html. por qué ?
const { WritableStream } = require("htmlparser2/lib/WritableStream"); const scriptPath = await new Promise(function(resolve, reject) { try { const parser = new WritableStream({ onopentag: (name, attrib) => { if (name === "script" && attrib.src) { console.log(`script : ${attrib.src}`); resolve(attrib.src); // return the first script, effectively called for each script tag // none of below calls seem to work indexStream.unpipe(parser); parser.emit("close"); parser.end(); parser.destroy(); } }, onend() { resolve(); } }); const indexStream = got.stream("/index.html", { responseType: 'text', resolveBodyOnly: true }); indexStream.pipe(parser); // and parse it } catch (e) { reject(e); } });
¿Es posible cerrar el flujo del analizador antes del final efectivo de indexStream y, en caso afirmativo, cómo? Si no, ¿por qué?
Tenga en cuenta que el código funciona y mi promesa se resuelve de manera efectiva utilizando la primera coincidencia.
Hay un poco de confusión sobre cómo funciona WriteableStream. En primer lugar, cuando haces esto:
const parser = new WritableStream(...)
eso es engañoso Realmente debería ser esto:
const writeStream = new WritableStream(...)
El analizador HTML real es una variable de instancia en el objeto WritableStream llamado ._parser
(ver código ). Y es ese analizador el que emite las devoluciones de llamada onopentag()
y debido a que está trabajando en un búfer que puede tener algo de texto acumulado que se desconecta del flujo de lectura, es posible que no detenga de inmediato los eventos que aún provienen de los datos almacenados en el búfer.
El analizador en sí tiene un método de reset()
y parece que si se desconecta del flujo de lectura y luego llamaste a ese método de reinicio, debería dejar de emitir eventos.
Puede probar esto (no soy una persona de TypeScript, por lo que es posible que tenga que modificar algunas cosas para hacer feliz al compilador de TypeScript, pero espero que pueda ver el concepto aquí):
const { WritableStream } = require("htmlparser2/lib/WritableStream"); const scriptPath = await new Promise(function(resolve, reject) { try { const writeStream = new WritableStream({ onopentag: (name, attrib) => { if (name === "script" && attrib.src) { console.log(`script : ${attrib.src}`); resolve(attrib.src); // return the first script, effectively called for each script tag // disconnect the readstream indexStream.unpipe(writeStream); // reset the internal parser so it clears any buffers it // may still be processing writeStream._parser.reset(); } }, onend() { resolve(); } }); const indexStream = got.stream("/index.html", { responseType: 'text', resolveBodyOnly: true }); indexStream.pipe(writeStream); // and parse it } catch (e) { reject(e); } });