javascript - web worker - 传回主线程时数据未定义
问题描述
我正在尝试使用网络工作者获取一些数据,然后将它们传递回主线程。我已尝试使用此代码,但无法按预期工作
onmessage = (e) => {
console.log(e);
if( e.data[0] === 'fetchData' ){
fetch('https://example.com/platform/api/v1/endpoint')
.then( (res) => res.json() )
.then( async (data) => {
const imagesData = await Promise.all(
data.map( async (item) => {
let res = await fetch(item.src);
let img = await res.blob();
let reader = new FileReader();
reader.readAsDataURL(img);
reader.onloadend = () => {
return {
title: item.title,
link: item.link,
src: reader.result
}
}
})
)
postMessage(imagesData);
})
}
}
a 之后的 imagesDataconsole.log
将包含一个由七个未定义元素组成的数组,我该如何解决这个问题?
更新
我已经在 vue 前端和工作人员中更改了代码,现在我能够获取数据,但有时工作人员将无法工作,我将无法获取数据,或者我只得到两个条目但预期number 是前端的七个项目。这是我修改代码的方式,也许我需要在使用另一个代码之前终止工作?注意:我正在创建一个选项卡覆盖 chrome 扩展
vue前端代码
<script>
const worker = new Worker('services.js');
export default {
name: 'App',
beforeCreate() {
worker.postMessage(['fetchData']);
},
created() {
this.init();
this.clock();
},
data() {
return {
mostVisited: [],
imagesData: [],
isLoading: true
}
},
methods: {
init() {
worker.onmessage = (e) => {
console.log(e);
this.imagesData = e.data;
this.isLoading = false;
}
browser.topSites.get().then( (sites) => this.mostVisited = sites );
} //end init
}
</script>
网络工作者代码
onmessage = (e) => {
console.log(e);
if( e.data[0] === 'fetchData' ){
fetch('https://example.com/platform/api/v1/endpoint')
.then( (res) => res.json() )
.then( async (data) => {
let imagesData = [];
await Promise.all(
data.map( async (item) => {
let res = await fetch(item.src);
let img = await res.blob();
let reader = new FileReader();
reader.readAsDataURL(img);
reader.onloadend = () => {
imagesData.push({ title: item.title, link: item.link, src: reader.result });
}
})
)
postMessage(imagesData);
}); // end then(data)
}
}
解决方案
在解析外部 Promise 之前,您不会等待异步 FileReader 读取您的文件,因此Promise 在之后但之前Promise.all
解析。let img = await res.blob();
onloadend
由于您处于 Worker 上下文中,因此您可以使用同步 FileReaderSync API,它会提供类似
.then( async (data) => {
let imagesData = [];
await Promise.all(
data.map( async (item) => {
let res = await fetch(item.src);
let img = await res.blob();
let reader = new FileReaderSync();
const result = reader.readAsDataURL(img);
imagesData.push({ title: item.title, link: item.link, src: result });
})
)
postMessage(imagesData);
});
但我有 99% 的信心认为您甚至不需要这些数据:URL,而且它的危害比任何事情都大。
请记住,来自 FileReader 的 data: URL 始终编码为 base64,这将生成一个包含 134% 原始数据的 DOMString,因为 DOMStrings 存储在 UTF-16 中,所以您将其乘以 2。
然后,要将数据传递到主上下文,浏览器必须使用结构化克隆算法序列化数据,对于 DOMStrings,这意味着在内存中的简单副本。现在,每个图像占用的内存大约是其实际大小的 5 倍,甚至在主上下文开始再次将其解析为二进制数据之前,它就可以构建像素数据......
相反,只需将获得的 Blob 传递为img
.
Blob 的内部数据由结构化克隆算法通过引用传递,因此您复制的所有内容都是小型 js 包装器。
然后,当您需要在主上下文中显示这些图像时,使用URL.createObejctURL(img)
which 将返回一个 blob: URL 直接指向同一个 Blob 的数据,该数据仍仅在内存中存储一次。
.then( async (data) => {
let imagesData = [];
await Promise.all(
data.map( async (item) => {
let res = await fetch(item.src);
let img = await res.blob();
const url = URL.createObjectURL(img);
imagesData.push({ title: item.title, link: item.link, src: url, file: img });
})
)
postMessage(imagesData);
});
推荐阅读
- css - 滚动div内的CSS div定位
- javascript - 使用多个 if 和对象键改进代码,javascript 中的值
- java - 不显示要移动到 JFrame 的图像
- node.js - npm init 不起作用,ENOENT:没有这样的文件或目录
- directory - 如何修复无限递归文件夹?
- kotlin - 如何在kotlin中将函数的返回类型设置为mutableListOf
- python - 加法计算器的工作没有显示
- javascript - 由于 MIME 类型,无法加载模块脚本
- dns - Office 365登录重定向到 GoDaddy SSO
- kubernetes - Kubernetes v1.20 端点资源无法查看控制器管理器或调度器