如何在用户脚本中替换已弃用的同步XMLHttpRequest?
解决Worker代码加载的跨域问题(非文件方式)
完全可以通过字符串或模板字面量直接为Worker提供代码,核心是将代码转为Blob对象生成同源URL,绕开外部文件的跨域限制,同时解决同步XHR的性能和弃用问题。
具体实现思路
- 将Worker的业务逻辑(比如异步获取包页面、解析类型分类)写成模板字面量字符串
- 把字符串转为
Blob对象,指定MIME类型为text/javascript - 用
URL.createObjectURL生成Blob的本地可访问URL,以此创建Worker实例
示例代码
// 定义Worker要执行的代码(模板字面量形式) const workerLogic = ` self.onmessage = async (event) => { const packagePageUrl = event.data; try { // 用异步fetch替代同步XHR,避免主线程阻塞 const response = await fetch(packagePageUrl); const pageHtml = await response.text(); // 解析HTML提取类型分类(I、C、Eₙ、Eₓ、Eᵣ、A) const typeGroups = parseTypeCategories(pageHtml); // 将结果发回主线程 self.postMessage({ success: true, data: typeGroups }); } catch (err) { self.postMessage({ success: false, error: err.message }); } }; // 实现HTML解析逻辑(Worker内可用DOMParser) function parseTypeCategories(html) { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const typeTable = doc.querySelector('table.summary-table'); const rows = typeTable?.querySelectorAll('tr') || []; const groups = { interfaces: [], classes: [], enums: [], exceptions: [], errors: [], annotations: [] }; rows.forEach(row => { const typeLink = row.querySelector('a'); const typeName = typeLink?.textContent.trim(); if (!typeName) return; const typeDesc = row.querySelector('td.col-last')?.textContent.trim() || ''; // 根据描述判断类型分类,比如"interface"对应I,"class"对应C等 if (typeDesc.includes('interface')) groups.interfaces.push(typeName); else if (typeDesc.includes('class')) groups.classes.push(typeName); else if (typeDesc.includes('enum')) groups.enums.push(typeName); else if (typeDesc.includes('exception')) groups.exceptions.push(typeName); else if (typeDesc.includes('error')) groups.errors.push(typeName); else if (typeDesc.includes('annotation')) groups.annotations.push(typeName); }); return groups; } `; // 创建Blob并生成Worker URL const codeBlob = new Blob([workerLogic], { type: 'text/javascript' }); const workerUrl = URL.createObjectURL(codeBlob); const typeParserWorker = new Worker(workerUrl); // 主线程与Worker通信 typeParserWorker.postMessage('https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/package-summary.html'); typeParserWorker.onmessage = (event) => { if (event.data.success) { // 用解析出的分类数据构建导航树 buildNavTree(event.data.data); } else { console.error('类型解析失败:', event.data.error); } // 释放URL资源,避免内存泄漏 URL.revokeObjectURL(workerUrl); typeParserWorker.terminate(); }; // 导航树构建函数(主线程执行,操作DOM) function buildNavTree(typeGroups) { // 你的导航树生成逻辑,比如创建DOM节点插入页面 console.log('类型分类结果:', typeGroups); }
核心优势
- 无需外部Worker文件,代码完全内嵌在用户脚本中
- Blob URL属于同源范围,不会触发跨域安全错误
- 异步fetch替代同步XHR,彻底解决主线程阻塞和浏览器弃用警告问题
注意事项
- Worker内部无法直接操作DOM,所有DOM修改必须回到主线程处理
- 任务完成后务必调用
URL.revokeObjectURL释放Blob URL资源 - 确保解析逻辑在Worker环境中兼容(比如使用
DOMParser而非直接访问页面DOM)
内容的提问来源于stack exchange,提问作者Gerold Broser
相关产品推荐
相关产品推荐

