Javascript web worker-返回主线程时未定义数据

Javascript web worker-返回主线程时未定义数据,javascript,vue.js,web-worker,Javascript,Vue.js,Web Worker,我正在尝试使用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)

我正在尝试使用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);
    })
  }
}
console.log之后的imagesData将包含七个未定义元素的数组,如何修复

更新

我已将vue前端中的代码更改为worker,现在我可以获取数据,但有时worker无法工作,我无法获取数据,或者我仅获取两个条目,但前端的预期数量为7项。下面是我如何修改代码的,也许我需要在使用另一个之前终止工作? 注意:我正在创建一个选项卡覆盖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>

您没有等待异步FileReader在解析外部承诺之前读取您的文件,因此
Promise.all
Promise在
let img=wait res.blob()之后解析但在
onloadend
之前

由于您处于工作上下文中,因此可以使用同步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,它会比任何东西都有害

请记住,文件读取器中的data:URL始终编码为base64,这将生成一个包含134%原始数据的DOMString,由于DOMString存储在UTF-16中,因此每2乘以一次。
然后,为了将数据传递到主上下文,浏览器必须使用序列化数据,对于DOMStrings,这意味着在内存中进行简单的复制。每个图像现在占用的内存大约是其实际大小的5倍,甚至在主上下文开始再次将其解析为二进制数据以便它可以构建像素数据之前

相反,只需将得到的Blob作为
img
传递
,因此,您只需复制周围的小js包装。
然后,当您需要在主上下文中显示这些图像时,使用它将返回一个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);
});

我不知道使用文件阅读器会占用大量内存,我认为这是隐藏原始资源直接链接的正确方法,但我错了。感谢您的解释,我将修改代码以应用您建议的修复。只是一件小事,我还需要将水滴传递到阵列中?我看到你已经将它链接到了被推到数组中的对象的文件密钥中。不,你没有,这是jist。我不知道你在用那个数据URL做什么。例如,如果在某个时候您需要将其上传回来,tjen直接使用Blob进行上传,那么再次通过postMessage传递它不需要任何费用。
.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);
});