You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用OMDB API的页面需点击两次提交才渲染HTML的问题求助

问题:首次点击搜索按钮无法渲染电影内容,需点击两次才生效

我正在制作一个练习用网站,通过OMDB API获取电影数据,用户搜索关键词后在页面展示对应的HTML内容。目前遇到问题:用户需要点击两次搜索按钮,页面才会渲染出电影HTML。API已正常响应并填充fullMovies数组,但首次点击时movieItemHTML函数生成的内容无法展示,第二次点击才生效。我猜测这与async/await的异步逻辑有关,但耗时3小时仍未排查出问题。

原代码

const form = document.getElementById('form');
const movieItem = document.querySelector('.movies');
const APIKEY = 'a3f1f778';
const exploring = document.querySelector('.exploring');
const searchInput = document.getElementById('query');

const movies = [];
const fullMovies = [];

form.addEventListener('submit', (e) => {
  e.preventDefault();

  getMovies();

  //   console.log(fullMovies);
});

const getMovies = async () => {
  const url = `http://www.omdbapi.com/?s=${searchInput.value}&apikey=${APIKEY}`;
  const res = await fetch(url);
  const movieData = await res.json();
  movieData.Search.forEach((e) => movies.push(e));
  searchMovieDetails();
};

const searchMovieDetails = () => {
  movies.forEach(async (e) => {
    const res = await fetch(
      `http://www.omdbapi.com/?t=${e.Title}&apikey=${APIKEY}`
    );
    const data = await res.json();
    fullMovies.push(data);
  });
  movieItemHTML();
};

function movieItemHTML() {
  exploring.style.display = 'none';
  let html = '';
  fullMovies.forEach((e) => {
    html = `
  <div class="movie-item">
    <img class="poster" src=${e.Poster}/>
    <div class="movie-desc">
        <div class="title-rating">
            <h3>${e.Title}</h3>
                <img src="./images/star.png" class="star"/>
                <p class="rating"> ${e.imdbRating}</p>
        </div>
        <div class="time-kind-btn">
            <p>${e.Runtime}</p>
            <p>${e.Genre}</p>
            <a class="watchlist"><img src="./images/addBtn.png"> Watchlist</a>
        </div>
        <div>
            <p class="plot">${e.Plot}</p>
        </div>
    </div>
  </div>
  `;
    movieItem.innerHTML += html;
  });
}

问题分析

  • searchMovieDetails中,forEach循环遍历异步函数时,不会等待每个异步请求完成就直接执行后续的movieItemHTML,此时fullMovies数组还没有被填充数据,所以首次点击没有内容渲染。
  • 全局数组movies和fullMovies未在每次搜索前清空,第二次点击时,第一次的异步请求刚好完成,数组积累了数据,因此能渲染出内容,但会导致旧数据叠加。

修复方案

1. 改造异步逻辑,等待所有详情请求完成

把forEach替换为Promise.all,确保所有电影详情请求都返回后再调用渲染函数,同时将searchMovieDetails改为异步函数。

2. 每次搜索清空全局数组

在getMovies开头清空movies和fullMovies,避免旧数据干扰新搜索结果。

3. 渲染前清空容器内容

在movieItemHTML开头清空movieItem的innerHTML,防止多次搜索内容叠加。

修改后的完整代码

const form = document.getElementById('form');
const movieItem = document.querySelector('.movies');
const APIKEY = 'a3f1f778';
const exploring = document.querySelector('.exploring');
const searchInput = document.getElementById('query');

let movies = [];
let fullMovies = [];

form.addEventListener('submit', (e) => {
  e.preventDefault();
  getMovies();
});

const getMovies = async () => {
  // 每次搜索清空数组
  movies = [];
  fullMovies = [];
  
  const url = `http://www.omdbapi.com/?s=${searchInput.value}&apikey=${APIKEY}`;
  const res = await fetch(url);
  const movieData = await res.json();
  
  if (!movieData.Search) return; // 处理无搜索结果的情况
  movies.push(...movieData.Search);
  await searchMovieDetails(); // 等待详情请求完成
};

const searchMovieDetails = async () => {
  // 使用Promise.all等待所有异步请求完成
  const detailPromises = movies.map(async (movie) => {
    const res = await fetch(`http://www.omdbapi.com/?t=${movie.Title}&apikey=${APIKEY}`);
    return await res.json();
  });
  
  fullMovies = await Promise.all(detailPromises);
  movieItemHTML();
};

function movieItemHTML() {
  exploring.style.display = 'none';
  // 清空容器内容,避免叠加
  movieItem.innerHTML = '';
  
  let html = '';
  fullMovies.forEach((e) => {
    html += `
  <div class="movie-item">
    <img class="poster" src="${e.Poster}"/>
    <div class="movie-desc">
        <div class="title-rating">
            <h3>${e.Title}</h3>
                <img src="./images/star.png" class="star"/>
                <p class="rating"> ${e.imdbRating}</p>
        </div>
        <div class="time-kind-btn">
            <p>${e.Runtime}</p>
            <p>${e.Genre}</p>
            <a class="watchlist"><img src="./images/addBtn.png"> Watchlist</a>
        </div>
        <div>
            <p class="plot">${e.Plot}</p>
        </div>
    </div>
  </div>
  `;
  });
  
  movieItem.innerHTML = html;
}

内容的提问来源于stack exchange,提问作者Biobrolly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:22:07