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

JS类异步数据处理:解决fetch请求后访问数据为空问题

问题核心原因

你遇到的是JavaScript异步执行机制的典型问题:fetch发起网络请求属于异步宏任务,构造函数中调用fetchNews()时,主线程不会等待接口响应返回、也不会等待Promise状态变更为resolved,就会直接往下执行后续的showNews()调用,此时类成员news还没被接口返回值赋值,自然读取到的是初始的空数组。
从你代码里的打印顺序就能验证:控制台永远会先打印B、C的空数组结果,最后才打印A的接口数据长度,就是异步任务被延后到同步任务执行完成后才触发的表现。
另外你原代码构造函数里单独写的this.news;是无效语句,没有任何实际作用,可以直接删掉。

可落地的调整方案

不要试图在构造函数里阻塞等待异步结果,构造函数本身不支持返回Promise来阻塞实例化流程,强行实现会让代码可维护性极差。推荐两种常用的实现方式:

方案1:最小改动,返回Promise实例控制执行顺序

只需要让fetchNews()方法返回内部的请求Promise,外部实例化后等待请求完成,再调用渲染方法即可,改动量最小:

class MyNews {
  news = [];
  apiUrl = "https://jsonplaceholder.typicode.com/posts";

  constructor() {
    // 移除原无效的this.news语句,构造函数里只做同步初始化
  }

  fetchNews() {
    // 返回整个请求的Promise链
    return fetch(this.apiUrl)
      .then(async (res) => {
        this.news = await res.json();
        console.log("A:", this.news.length);
        return this.news;
      })
      .catch((err) => {
        console.log("请求异常:", err);
        throw err;
      });
  }

  showNews() {
    console.log("B:", this.news.length);
    // 这里直接写DOM渲染逻辑即可,比如遍历this.news生成li标签插入页面列表容器
    return this.news;
  }
}

// 实例化+调用逻辑
const newsInstance = new MyNews();
// 等待数据拉取完成后再执行渲染
newsInstance.fetchNews().then(() => {
  console.log("C:", newsInstance.showNews().length);
  // 所有依赖新闻数据的HTML渲染逻辑都放在这个回调里执行
});

方案2:async/await语法改造,逻辑更贴近同步写法

如果不习惯链式then的写法,可以用async/await改造,代码逻辑更直观:

class MyNews {
  news = [];
  apiUrl = "https://jsonplaceholder.typicode.com/posts";

  // 标记方法为async
  async fetchNews() {
    try {
      const res = await fetch(this.apiUrl);
      this.news = await res.json();
      console.log("A:", this.news.length);
      return this.news;
    } catch (err) {
      console.log("请求异常:", err);
      throw err;
    }
  }

  showNews() {
    // 加个防御性判断,避免未加载完成时调用报错
    if (!this.news.length) {
      console.warn("新闻数据尚未加载完成");
      return [];
    }
    console.log("B:", this.news.length);
    // DOM渲染逻辑写在这里
    return this.news;
  }
}

// 用自执行async函数包裹初始化逻辑
(async () => {
  const newsInstance = new MyNews();
  await newsInstance.fetchNews();
  const newsList = newsInstance.showNews();
  console.log("C:", newsList.length);
  // 执行后续列表渲染操作
})();
额外优化建议
  • 可以在调用fetchNews()之前先给页面渲染“数据加载中”的占位提示,等接口返回、showNews()执行时再替换成真实内容,提升用户体验。
  • 不要把异步请求的结果赋值完全和渲染逻辑割裂,后续如果要做刷新、分页等功能,只需要重新调用fetchNews(),数据更新完成后再触发showNews()重渲染即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 01:42:36