如何保证HTML字段始终填充最后一次发起的API请求返回的数据?
问题原因
你遇到的是异步请求的竞态条件问题:网络请求的返回顺序不受发起顺序控制,更早发起的请求可能后返回,导致旧数据覆盖了后续新请求应该渲染的结果。
解决方案
这里提供两种实现简单、改造成本低的方案:
方案1:新增标识过滤旧请求(零延迟,实时请求)
只需要新增1个全局变量做校验,不需要修改原有逻辑,就能保证永远只渲染最后一次请求的结果:
const pokemonId = document.getElementById("pokemon-id"); const pokemonName = document.getElementById("pokemon-name"); const pokemonType = document.getElementById("pokemon-type"); const pokemonHeight = document.getElementById("height"); const pokemonWeight = document.getElementById("weight"); const pokemonSearch = document.getElementById("pokemon-search"); // 新增:记录最新的搜索值 let latestSearch = ''; async function fetchPokemon(idOrName) { const endpoint = "https://pokeapi.co/api/v2/pokemon/"; const response = await fetch(endpoint + idOrName); if (!response.ok) return null; return response.json(); } function fillPokemonFields(pokemon) { if(!pokemon) return; pokemonId.textContent = pokemon.id; pokemonName.textContent = pokemon.name; pokemonType.textContent = pokemon.type; pokemonHeight.textContent = pokemon.height; pokemonWeight.textContent = pokemon.weight; } pokemonSearch.addEventListener("input", async function () { let input = this.value.trim(); // 每次触发输入都更新最新搜索值 latestSearch = input; if (!input) return; let pokemon = await fetchPokemon(input); // 只有当前请求的输入值等于最新搜索值时,才渲染结果 if (input === latestSearch) { fillPokemonFields(pokemon); } });
方案2:防抖优化(减少请求数,体验更友好)
如果不需要输入实时触发请求,可以加防抖逻辑,用户连续输入时不会频繁发起请求,只会在停止输入固定时长后发起一次请求,从根源上避免多请求并发的竞态问题:
const pokemonId = document.getElementById("pokemon-id"); const pokemonName = document.getElementById("pokemon-name"); const pokemonType = document.getElementById("pokemon-type"); const pokemonHeight = document.getElementById("height"); const pokemonWeight = document.getElementById("weight"); const pokemonSearch = document.getElementById("pokemon-search"); // 防抖工具函数,delay可自行调整,默认300ms function debounce(func, delay = 300) { let timer = null; return function(...args) { clearTimeout(timer); timer = setTimeout(() => func.apply(this, args), delay); } } async function fetchPokemon(idOrName) { const endpoint = "https://pokeapi.co/api/v2/pokemon/"; const response = await fetch(endpoint + idOrName); if (!response.ok) return null; return response.json(); } function fillPokemonFields(pokemon) { if(!pokemon) return; pokemonId.textContent = pokemon.id; pokemonName.textContent = pokemon.name; pokemonType.textContent = pokemon.type; pokemonHeight.textContent = pokemon.height; pokemonWeight.textContent = pokemon.weight; } // 用防抖函数包裹原回调逻辑 pokemonSearch.addEventListener("input", debounce(async function () { let input = this.value.trim(); if (!input) return; let pokemon = await fetchPokemon(input); fillPokemonFields(pokemon); }));
内容的提问来源于stack exchange,提问作者skillsboy
相关产品推荐
相关产品推荐

