英文:
Javascript - Need to click submit form twice to get html printed - OMDB api
问题
以下是您的代码的中文翻译部分:
// 我正在尝试创建一个用于练习的网站,该网站从OMDB API获取电影,并在用户搜索后在页面上显示HTML。
// 问题是用户需要点击搜索按钮两次才能显示HTML。
// API响应并填充我的数组(fullMovies),但HTML(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();
});
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;
});
}
请注意,我已经将HTML标记和JavaScript代码翻译为中文。如果您需要进一步的帮助,请随时提出。
英文:
I am trying to make a site for practice that gets the movies from the OMDB api and displays the HTML on the page once the user searches for a term.
The problem is that the user needs to click the search button twice for the html to appear.
The api responds and populates my Array (fullMovies) but the html (movieItemHTML function) does not get displayed on the first click but on the second
I am guessing it has something to do with async await but for the past 3 hours I can not figure it out.
Any help appreciate it!
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;
});
}
答案1
得分: 1
这是代码部分,不需要翻译:
function getMovies(searchInput, APIKEY){
fetch(`http://www.omdbapi.com/?s=${searchInput.value}&apikey=${APIKEY}`)
.then(r => r.json())
.then(j => Promise.all(j.Search.map(m => fetch(`http://www.omdbapi.com/?t=${m.Title}&apikey=${APIKEY}`)
.then(r => r.json())
)
)
)
.then(movies => movies.forEach(appendMovieToWhateverDOMElement))
.catch(handleError);
}
翻译好的部分:
"这是因为searchMovieDetails()
函数在fullMovies
数组填充之前同步调用了movieItemHTML()
函数。不好意思,但这是一段代码在很多方面都很糟糕。主要是副作用会让你误以为你在第二次点击时会得到它们。
除非你确实需要它们,否则要远离异步函数。异步操作不应该被实现得像同步命令式代码一样。这是 JavaScript 的一个缺陷。
你可以使用一个函数来完成这个任务。"
英文:
It happens because the searchMovieDetails()
function invokes movieItemHTML()
function synchronously even before the fullMovies
array gets populated. And sorry but this is a terrible code on many levels. Primiarily the side effects deceive you to believe that you get them on the second click.
Stay away from the async functions unless you really need them if you ever do. Asynchronous operations shouldn't be implemented as if they are synchronous imperative code. This is a wart of JS.
You can use a single function for this job.
function getMovies(searchInput, APIKEY){
fetch(`http://www.omdbapi.com/?s=${searchInput.value}&apikey=${APIKEY}`)
.then(r => r.json())
.then(j => Promise.all(j.Search.map(m => fetch(`http://www.omdbapi.com/?t=${m.Title}&apikey=${APIKEY}`)
.then(r => r.json())
)
)
)
.then(movies => movies.forEach(appendMovieToWhateverDOMElement))
.catch(handleError);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论