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

JavaScript async函数await fetch未等待致artists数组为空修复

问题说明

对接Spotify API实现艺术家信息校验功能时,运行后artists[]始终为空,本质是异步执行时序错误:fetch请求未执行完成时,就提前完成了user变量的赋值,此时artists数组还未完成填充。

原有实现代码:

let artists = []

function setArtists(input) {
  artists.length = 0
  let parsedInput = input.value.split(",")
  parsedInput.forEach(artist => {
    validateArtist(artist)
  })
}

async function validateArtist(s) {
  let token = localStorage.getItem("Token")
  let url = "https://api.spotify.com/v1/search?type=artist&q=" + s
  console.log(url)
  await fetch(url, {
      "method": "GET",
      "headers": {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        "Authorization": "Bearer " + token,
      }
    })
    .then(response => {
      if (response.status === 401) {
        refreshToken(s)
      }
      return response.json()
    })
    .then(searchedResults => searchedResults.artists.items.length != 0)
    .then(isArtist => {
      if (isArtist) {
        artists.push(s)
      }
    })
}

原有调用逻辑:

setArtists(document.getElementById("artistiPreferiti"))
var user = {
        username: document.getElementById("username").value,
        email: document.getElementById("email").value,
        password: document.getElementById("password").value,
        gustiMusicali: document.getElementById("gustiMusicali").value,
        artistiPreferiti: artists
}    
问题根因
  • setArtists是同步函数,内部通过forEach调用异步的validateArtist时,没有接收、等待异步任务的执行结果,触发所有校验请求后就直接退出了函数
  • 外层构造user对象是同步逻辑,调用setArtists后不会等待所有接口返回,直接读取了当前还是空值的artists数组赋值
  • 接口返回401时调用refreshToken没有加await,即使触发token刷新,也不会等待刷新完成就继续执行后续逻辑,鉴权流程存在时序漏洞
  • 搜索关键词未做URL编码,艺术家名称包含空格、特殊符号时请求会异常
修复方案
  1. 将setArtists改为异步函数,用Promise.all配合map等待所有艺术家校验请求全部完成,替换无法处理异步等待的forEach写法
  2. 统一用async/await写法替换原有的.then()链式调用,避免漏写等待导致时序错误
  3. 外层调用setArtists时加await,等数组填充完成后再构造user对象
  4. 补全401场景下的等待、重试逻辑,对搜索关键词做URL编码,赋值时做数组浅拷贝避免引用类型副作用

修复后的完整代码:

let artists = []

async function setArtists(input) {
  artists.length = 0
  // 拆分输入后顺手去除每个艺术家名前后的空格
  let parsedInput = input.value.split(",").map(name => name.trim())
  // 等待所有校验请求执行完成
  await Promise.all(
    parsedInput.map(artist => validateArtist(artist))
  )
}

async function validateArtist(s) {
  let token = localStorage.getItem("Token")
  // 对搜索关键词做URL编码,避免特殊字符导致请求异常
  let url = "https://api.spotify.com/v1/search?type=artist&q=" + encodeURIComponent(s)
  console.log(url)
  const response = await fetch(url, {
    method: "GET",
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      "Authorization": "Bearer " + token,
    }
  })
  // 401时等待token刷新完成,再重试当前校验请求
  if (response.status === 401) {
    await refreshToken(s)
    return validateArtist(s)
  }
  const searchedResults = await response.json()
  const isArtist = searchedResults.artists.items.length !== 0
  if (isArtist) {
    artists.push(s)
  }
}

修复后的调用逻辑(需要放在async函数内才能使用await):

async function handleSubmit() {
  // 等待所有校验完成、artists数组填充完毕
  await setArtists(document.getElementById("artistiPreferiti"))
  const user = {
    username: document.getElementById("username").value,
    email: document.getElementById("email").value,
    password: document.getElementById("password").value,
    gustiMusicali: document.getElementById("gustiMusicali").value,
    // 浅拷贝数组,避免后续artists变动影响user对象的属性值
    artistiPreferiti: [...artists]
  }
  // 后续执行提交等逻辑即可
}
注意事项
  • 不要在循环中直接触发异步函数而不等待结果,forEach本身没有返回值,无法配合await等待异步任务执行
  • 混用async/await和.then()链容易漏写等待逻辑,统一写法能大幅降低异步时序bug的概率
  • JS中数组、对象属于引用类型,直接赋值时只是传递内存地址,后续原变量改动会同步影响赋值后的属性,必要时需要做浅/深拷贝

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:15:48