在Web Worker中,如何从字符串中查找html属性?

问题描述 投票:0回答:2

在网络工作者内部,我有一个 html 字符串,例如:

"<div id='foo'>  <img src='bar'></img>  <ul id='baz'></ul>  </div>"

有没有我可以导入的库来轻松访问不同标签的 id 和 src 属性?正则表达式是工作人员内部的唯一方法吗?

javascript dom web-worker
2个回答
2
投票

有两种方法可以有效解决这个问题:

正则表达式

由于存在误报的风险,您可以使用以下内容:

var pattern = /<img [^>]*?src=(["'])((?:[^"']+|(?!\1)["'])*)(\1)/i;
var match = string.match(pattern);
var src = match ? match[2] : '';

内置解析器和消息传递

如果获得正确的 HTML 是一个关键要求,只需让浏览器通过将字符串传递给调用者来解析 HTML。这是一个完整的例子:

来电者:

var worker = new Worker('worker.js');
worker.addEventListener('message', function(e) {
    if (!e.data) return;
    if (e.data.method === 'getsrc') {
        // Unlike document.createElement, etc, the following method does not 
        //  load the image when the HTML is parsed
        var doc = document.implementation.createHTMLDocument('');
        doc.body.innerHTML = e.data.data;
        var images = doc.getElementsByTagName('img');
        var result = [];
        for (var i=0; i<images.length; i++) {
            result.push(images[i].getAttribute('src'));
        }
        worker.postMessage({
            messageID: e.data.messageID,
            result: result
        });
    } else if (e.data.method === 'debug') {
        console.log(e.data.data);
    }
});

worker.js

// A simple generic messaging API
var callbacks = {};
var lastMessageID = 0;
addEventListener('message', function(e) {
   if (callbacks[e.data.messageID]) {
       callbacks[e.data.messageID](e.data.result);
   }
});
function sendRequest(method, data, callback) {
    var messageID = ++lastMessageID;
    if (callback) callbacks[messageID] = callback;
    postMessage({
        method: method,
        data: data,
        messageID: messageID
    });
}

// Example:
sendRequest('getsrc',
    '<img src="foo.png">' + 
    "<img src='bar.png'>" + 
    '<textarea><img src="should.not.be.visible"></textarea>',
    function(result) {
        sendRequest('debug', 'Received: ' + result.join(', '));
    }
);

0
投票

2023 年,差不多 11 年后,还有更多选择。

为了仅扫描 HTML 字符串中的元素,

htmlparse2
通常就足够了:

// Demo using htmlparser2 in a web worker
const WORKER_URL = URL.createObjectURL(
  new Blob(
    [
      `
import { Parser } from 'https://esm.sh/[email protected]';

self.addEventListener('message', (event) => {
  const ids = [];
  const srcs = [];
      
  const parser = new Parser({
    onopentag(name, attributes) {
      if ('id' in attributes) {
        ids.push({ value: attributes.id, tag: name });
      }
      if ('src' in attributes) {
        srcs.push({ value: attributes.src, tag: name });
      }
    },
  });
  parser.write(event.data);
  parser.end();
      
  self.postMessage({ ids, srcs });
});
`,
    ],
    { type: 'text/javascript' }
  )
);

type AttributeMatch = {
  value: string;
  tag: string;
};

type FromWorker = {
  ids: AttributeMatch[];
  srcs: AttributeMatch[];
};

const worker = new Worker(WORKER_URL, { type: 'module' });

worker.addEventListener('message', (e) => {
  const { ids, srcs } = e.data as FromWorker;
  for (const id of ids) {
    console.log(`id="${id.value}" on <${id.tag}>`);
  }

  for (const src of srcs) {
    console.log(`src="${src.value}" on <${src.tag}>`);
  }
});

const input =
  '<div id="foo">  <img src="bar"></img>  <ul id="baz"></ul>  </div>';

worker.postMessage(input);

/*  console output:
    id="foo" on <DIV>
    id="baz" on <UL>
    src="bar" on <IMG>
 */

htmlparser2
是一个基于事件的解析器,实现
ontagname
事件处理程序
足以满足原始用例。

LinkeDOM (GitHub) 是一个更丰富的替代方案,非常有用,因为它提供了很多熟悉的 DOM API 函数,包括

document.createNodeIterator()
document.createTreeWalker()
:

// Demo using linkedom/worker in a web worker
import { parseHTML, NodeFilter } from 'https://esm.sh/[email protected]/worker';

self.addEventListener('message', (event) => {
  const ids = [];
  const srcs = [];

  const { document } = parseHTML(event.data);
  const i = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT);

  for (let element = i.nextNode(); element !== null; element = i.nextNode()) {
    const id = element.getAttribute('id');
    if (id) ids.push({ value: id, tag: element.tagName });

    const src = element.getAttribute('src');
    if (src) srcs.push({ value: src, tag: element.tagName });
  }

  self.postMessage({ ids, srcs });
});

请注意,在

linkedom/worker
中,
HTMLCanvasElement
本质上是一个存根。

© www.soinside.com 2019 - 2024. All rights reserved.