簡體   English   中英

Node.js htmlparser2 writableStream 在 end() 調用后仍然發出事件

[英]Node.js htmlparser2 writableStream still emit events after end() call

很抱歉這個可能微不足道的問題,但我仍然無法了解流在 node.js 中的工作方式。

我想解析一個 html 文件並獲取我遇到的第一個腳本的路徑。 我想在第一次匹配后中斷解析,但仍然調用 onopentag() 偵聽器,直到 html 文件有效結束。 為什么?

  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);
    }
  });

是否可以在 indexStream 有效結束之前關閉解析器 stream ,如果可以,如何? 如果不是為什么?

請注意,代碼有效,我的 promise 使用第一個匹配有效地解決了。

關於 WriteableStream 的工作原理有些混亂。 首先,當你這樣做時:

const parser = new WritableStream(...)

這是誤導。 真的應該是這樣的:

const writeStream = new WritableStream(...)

實際的 HTML 解析器是 WritableStream object 中名為._parser的實例變量(參見代碼)。 而且,正是那個解析器發出了onopentag()回調,並且因為它正在處理一個可能有一些累積文本與讀取流斷開連接的緩沖區,因此可能不會立即停止仍然來自緩沖數據的事件。

解析器本身有一個公共的reset() 方法,如果從 readstream 斷開連接,然后您調用了該 reset 方法,它應該停止發出事件。

你可以試試這個(我不是 TypeScript 的人,所以你可能需要按摩一些東西才能讓 TypeScript 編譯器滿意,但希望你能在這里看到這個概念):

  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);
    }
  });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM