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

OpenWeatherMap API集成报错:Uncaught (in promise) TypeError: locations is not iterable

解决OpenWeatherMap Geo API集成时的"locations is not iterable"错误

错误根源

你遇到的TypeError: locations is not iterable,本质是OpenWeatherMap的地理编码API返回的数据不是你预期的数组:

  • 当搜索词匹配到有效地点时,API返回地点数组;
  • 当搜索词无匹配、请求参数格式错误时,API会返回包含错误信息的对象(示例:{"cod":"404","message":"city not found"}),此时你尝试遍历这个对象就会触发错误。

修复步骤

1. 先确认API返回的数据结构

在api.js的fetchData中添加临时日志,查看实际返回内容:

export const fetchData = function (URL, callback) {
  fetch(`${URL}&appid=${api_key}`)
    .then((res) => res.json())
    .then((data) => {
      console.log('API返回数据:', data); // 新增日志
      callback(data);
    });
};

搜索一个不存在的地点,就能看到错误格式的返回结果。

2. 修改fetchData处理响应错误

OpenWeatherMap API会通过HTTP状态码和返回体的cod字段标识错误,在fetchData中提前处理这些情况:

export const fetchData = function (URL, callback) {
  fetch(`${URL}&appid=${api_key}`)
    .then((res) => {
      if (!res.ok) throw new Error(`请求失败: ${res.status}`);
      return res.json();
    })
    .then((data) => {
      // 检查是否为API返回的错误对象
      if (data.cod && data.cod !== 200) {
        throw new Error(data.message || '未知API错误');
      }
      callback(data);
    })
    .catch((err) => {
      console.error('数据获取失败:', err);
      callback([]); // 回调传入空数组,避免后续遍历报错
    });
};

3. 在app.js的回调中增加类型判断

即使fetchData处理了错误,也建议在回调里先确认locations是数组再执行遍历操作:

fetchData(url.geo(searchField.value), function (locations) {
  // 先判断是否为数组
  if (!Array.isArray(locations)) {
    searchResult.innerHTML = '<p class="error">未找到匹配地点</p>';
    searchField.classList.remove("searching");
    return;
  }

  // 正常处理数组的代码...
});

代码优化建议

改用Async/Await替代回调

回调嵌套会降低代码可读性,把fetchData改成返回Promise的形式:

// api.js
export const fetchData = async function (URL) {
  const res = await fetch(`${URL}&appid=${api_key}`);
  if (!res.ok) throw new Error(`请求失败: ${res.status}`);
  const data = await res.json();
  if (data.cod && data.cod !== 200) {
    throw new Error(data.message || '未知API错误');
  }
  return data;
};

// app.js
searchTimeout = setTimeout(async () => {
  try {
    searchField.classList.add("searching");
    const locations = await fetchData(url.geo(searchField.value));
    if (!Array.isArray(locations)) {
      searchResult.innerHTML = '<p class="error">未找到匹配地点</p>';
      return;
    }
    // 处理locations数组的代码...
  } catch (err) {
    console.error(err);
    searchResult.innerHTML = `<p class="error">${err.message}</p>`;
  } finally {
    searchField.classList.remove("searching");
  }
}, searchTimeoutDuration);

修复搜索防抖逻辑

你当前的searchTimeout ?? clearTimeout(searchTimeout)写法有误,应该改成:

// 无论超时是否存在,都清除之前的定时器
if (searchTimeout) clearTimeout(searchTimeout);

??是空值合并运算符,仅当searchTimeout为null/undefined时才执行右侧代码,无法清除已存在的超时任务。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 20:15:26