异步问题过滤器无法正常工作,因为数组为空

时间:2017-09-30 10:25:47

标签: javascript html api asynchronous promise

您好我有一个异步问题,当我尝试过滤audioFile数组时它是空的我需要在过滤器之前进行提取,我该怎么办?



const media = 'audio';
const searchInput = document.querySelector('.search');
const output = document.querySelector('.output')

searchInput.addEventListener('change', searchData);

async function searchData() {
  let search = this.value;
  const finalData = await getData(search);
  render(finalData);
}

function render(data) {
    let html;
if(media == 'image') {
   html = data.map(result => {
    return `
        <div class="image">
            <img src="${result.links[0].href}"/>
        </div>
    `
  }).join("");
} else {
          const audioFiles = [];
          data.map(result => {
            fetch(result.href)
            .then(blob => blob.json())
            .then(data => audioFiles.push(...data));
          })
          console.log(audioFiles);
          /* filter .mp3? */
          const regex = new RegExp(".mp3$");
          const files = audioFiles.filter(file => {
            return file.match(regex);
          })

          console.log(files);

}
output.innerHTML = html;

}

function getData(search) {
  const endpoint = `https://images-api.nasa.gov/search?q=${search}&media_type=${media}`;

  return fetch(endpoint)
    .then(blob => blob.json())
    .then(data => data.collection.items);
}
&#13;
<input type="text" class="search" placeholder="planet">
<div class="output"></div>
&#13;
&#13;
&#13;

音频文件在过滤器之前是空的我如何修复它所以音频文件在那里之前我做了过滤器???

2 个答案:

答案 0 :(得分:1)

看起来您可以将更多.then()链接到现有的。{/ p>

问题是:

      data.map(result => {
        fetch(result.href)
        .then(blob => blob.json())
        .then(data => audioFiles.push(...data));
      })

      // This part below is executing before `audiofiles` is populated
      console.log(audioFiles);
      /* filter .mp3? */
      const regex = new RegExp(".mp3$");
      const files = audioFiles.filter(file => {
        return file.match(regex);
      })

      console.log(files);

尝试:

      data.map(result => {
        fetch(result.href)
        .then(blob => blob.json())
        .then(data => audioFiles.push(...data))
        .then(() => new RegExp(".mp3$"))
        .then((regex) => audioFiles.filter(file => file.match(regex)))
        .then((files) => {
          console.log(files)

          // Set the HTML once it is done getting the audio
          output.innerHTML = html
        })
      })

我们正在使用implicit returns

此:

runFunction().then(data => console.log(data))

与:

相同
runFunction().then(data => {
  return console.log(data)
})

如果函数只返回一个表达式,甚至是.then(data => data += 5)

您必须考虑执行原始代码时JavaScript正在执行的操作。首先,它开始获取音频文件,它返回一个Promise,因此它立即被放入function queue,然后继续执行代码。它首先执行console.log(audiofiles),但函数队列中的提取还没有被推入audiofiles,因为2毫秒前,Promise链开始执行blob.json()。然后,它继续向下遍历您的代码并创建new RegExp并同步设置files的值,因为.filter()是同步的。然后它执行console.log(files),其中包含一些垃圾,因为音频文件可能会或可能没有数据被推入其中。合理地,在大多数情况下,还没有价值。

解决方案是强制代码等待,并且你已经使用了一些async / await语法,所以你也可以在这里使用它...

这可能是一个更易于阅读,扩展和维护的更好的解决方案:

} else {
  data.map(result => fetch(result.href))
      .then(async (blob) => {
         const data = await blob.json();

         const audiofiles = [...data];
         console.log(audioFiles);

         /* filter .mp3? */
         const regex = new RegExp(".mp3$");

         const files = audioFiles.filter(file => file.match(regex));
         console.log(files);

         output.innerHTML = html;
       })
}

我将您的代码解释为最后加载html,但是根据正确的异步行为,如果页面加载ASAP并且音频文件在准备就绪后加载,那么它将是最佳的。这可能是您的初衷,在这种情况下,将其移回if/else区域之外。

答案 1 :(得分:0)

你应该等待来自fetch的共鸣才能过滤它们,我希望渲染功能也可以异步

const media = 'audio';
const searchInput = document.querySelector('.search');
const output = document.querySelector('.output')

searchInput.addEventListener('change', searchData);

async function searchData() {
  let search = this.value;
  const finalData = await getData(search);
  render(finalData);
}

async function render(data) {
    let html;
if(media == 'image') {
   html = data.map(result => {
    return `
        <div class="image">
            <img src="${result.links[0].href}"/>
        </div>
    `
  }).join("");
} else {
          const regex = new RegExp(".mp3$");

          const files = await Promise.all(data.map(async result => {
            const response = await fetch(result.href)
            const blob = await blob.json()
            return blob.filter(file => file.match(regex));
          }))

          console.log(files);

}
output.innerHTML = html;

}

function getData(search) {
  const endpoint = `https://images-api.nasa.gov/search?q=${search}&media_type=${media}`;

  return fetch(endpoint)
    .then(blob => blob.json())
    .then(data => data.collection.items);
}
<input type="text" class="search" placeholder="planet">
<div class="output"></div>