【问题标题】:Uncaught (in promise) TypeError: Cannot read property 'forEach' of undefined未捕获(承诺中)类型错误:无法读取未定义的属性“forEach”
【发布时间】:2018-10-29 23:09:12
【问题描述】:

我正在尝试从 OMDB 数据库中获取数据以显示电影。最初我已经实现了点击事件来调用数据并且没有发现错误。但是当我切换到 keyup 事件时,我得到了这个错误。

Uncaught (in promise) TypeError: Cannot read property 'forEach' of undefined 在 fetchMovie.getMovies.then.res (main.js:27) fetchMovie.getMovies.then.res@main.js:27 异步函数(异步) searchInput.addEventListener@main.js:19

   let searchInput = document.getElementById('search')

    class fetchData {
    constructor() {
        this.apiKey = 'here is APIKey'
    }

    async getMovies(movie) {
        const movieRes = await fetch(`http://www.omdbapi.com/?apikey=${this.apiKey}&s=${movie}`)
        const moveData = await movieRes.json()
        return {
            moveData
        }
    }
      }
    const fetchMovie = new fetchData

    searchInput.addEventListener('keyup', (e) => {
    let input = e.target.value

    if (input !== '') {
        fetchMovie.getMovies(input)
            .then(res => {
                let data = res.moveData.Search
                let output = ''
                data.forEach(movie => {
                    output += `
                    <div class="col-md-3">
                    <div class="card" style="width: 18rem;">
                    <img class="card-img-top" src="${movie.Poster}" alt="Card image cap">
                    <div class="card-body">
                      <h5 class="card-title">${movie.Title}</h5>
                      <p class="card-text">${movie.Year}</p>
                      <a href="#" class="btn btn-primary">Go somewhere</a>
                    </div>
                  </div>
                    </div>`
                });
                document.getElementById('container').innerHTML = output;
            })
    }
    e.preventDefault();
    })

截图

用空图像修复的错误还添加了 keyup 事件。控制台没有错误

    let searchInput = document.getElementById('search');

class fetchData {

    constructor() {
        this.apiKey = '884df292'
    }

    async getMovies(movie) {
        const movieRes = await fetch(`http://www.omdbapi.com/?apikey=${this.apiKey}&s=${movie}`)
        const moveData = await movieRes.json()
        return {
            moveData
        }
    }
}
const fetchMovie = new fetchData

searchInput.addEventListener('keyup', (e) => {
    let input = e.target.value;

    if (input !== '') {
        fetchMovie.getMovies(input)
            .then(res => {
                let data = res.moveData.Search
                console.log(data)
                if (!data) {
                    return false
                } else {
                    let output = ''
                    data.forEach(movie => {
                        let poster
                        if (movie.Poster === "N/A") {
                            poster = `https://upload.wikimedia.org/wikipedia/commons/a/ac/No_image_available.svg`
                        } else {
                            poster = movie.Poster
                        }
                        output += `
                    <div class="col-md-3 movie-card">
                    <div class="card">
                    <img class="card-img-top" src="${poster}" alt="Card image cap">
                    <div class="card-body">
                      <h5 class="card-title">${movie.Title}</h5>
                      <p class="card-text">${movie.Year}</p>
                      <a href="#" class="btn btn-primary">Go somewhere</a>
                    </div>
                  </div>
                    </div>`
                    });
                    document.getElementById('container').innerHTML = output;
                }
            })
            .catch(err => console.log(err))
    }
    e.preventDefault();
})

【问题讨论】:

  • 如果你依赖于用户输入,你应该明确地添加适当的错误处理
  • 您获取电影的方式可能存在错误。我不熟悉 API,但您的错误上方可能有两行拼写错误。你输入了res.moveData,而你的意思可能是res.movieData
  • 尝试记录 res.moveData 是什么。
  • @MichaelKarpinski 尽管在任何地方都没有movieData,但moveData 工作得很好——很确定这只是一个缩写,而不是拼写错误
  • 如果res.moveData 是一个电影数组,那么它就不是一个属性为Search 的对象,所以当然访问moveData.Search 是未定义的......

标签: javascript api async-await fetch


【解决方案1】:

如果您看到您首先获得的日志屏幕截图并记录了undefined。这很可能是因为每次按键都会发生提取,如果您在 API 中搜索单个字符(这是您使用第一个 keyup 发送的内容),您将没有返回任何结果,因此forEach 失败。

在执行forEach 之前检查数据是否具有值,或者如果搜索字符串是单个字符,则甚至不发送获取。

let data = res.moveData.Search
let output = ''
if (!data) return; //early break if not results where returned.

或将if (input !== '') {改为

if (input.trim().length > 1) { // only do the fetch if more than one characters where entered

尽管即使您发送了多个字符,您仍可能得不到任何结果,因此第一种方法更安全。

【讨论】:

  • 真的,我也有同样的想法。您能否编辑我的代码以包含验证?
  • @Damian 刚刚为它添加了两个 sn-ps。
  • 工作。但我还有另一件事 /C:/Users/Damian/Desktop/movieinfo-master/N/A:1 GET file:///C:/Users/Damian/Desktop/movieinfo-master/N/A 0 () Image (异步) fetchMovie.getMovies.then.res @ main.js:41 Promise.then (异步) searchInput.addEventListener @ main.js:24
  • @Damian 关于您遇到的错误。那是因为有些图像没有海报,并且他们为该字段返回“N/A”。然后,您尝试将图像设置到该 url 并发生错误。您需要检查海报是否为“N/A”并且仅当它没有添加到您的代码中。
  • @Damian 发出一个请求(因为它们是异步的)在一个请求之后结束,您应该在发送新请求时中止之前的请求。请参阅 AbortController 接口了解如何操作developer.mozilla.org/en-US/docs/Web/API/AbortController/abort
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
  • 2017-08-12
  • 1970-01-01
  • 2021-05-13
  • 1970-01-01
  • 2023-03-31
  • 2020-11-09
相关资源
最近更新 更多