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

如何让API调用代码同步执行?解决后续JS依赖加载问题

问题描述

我写了一段通过fetch调用API并把响应存到window全局对象的代码,后续所有JS文件都依赖这个全局数据,但现在API调用是异步的,导致后续代码执行时数据还没加载完成。我需要让后续JS代码必须等API调用完成、数据存入全局对象后再执行,而且没法用.then这类链式调用的方式——因为这段代码是HTML里第一个引入的脚本,后面跟着多个依赖它的JS文件。

代码示例:

class GlobalConstants {
  constructor() {
    this.dynamicData = {}; 
    this.getConfigData(); 
  }

  async getConfigData() {
    try {
      const configResponse = await fetch("https://jsonplaceholder.typicode.com/todos/1");
      if (configResponse.status === 200) {
        const dummyData = await configResponse.json();
        this.dynamicUrl = dummyData; // 原代码笔误,应该赋值给dynamicData
      } else {
        throw new Error(`Config API 返回状态码: ${configResponse.status}`);
      }
    } catch (error) {
      console.warn("获取配置失败:", error);
    }
  }
}

window.globalConstants = new GlobalConstants();

console.log(globalConstants.dynamicData) // 当前会输出空对象,需要输出API响应结果

对应的HTML结构:

<!DOCTYPE HTML>
<html>
<head>
    <script src="https://test.com/script1.js"></script> <!-- 包含上述共享代码 -->
    <script src="https://test.com/script2.js"></script> <!-- 依赖该数据,需在API调用完成后执行 -->
    <script src="https://test.com/script3.js"></script> <!-- 同样依赖第一个脚本的响应数据 -->
 </head>
<body>
 <div id="body"></div>
</body>
</html>

最佳解决方案

方案1:异步初始化+动态加载依赖脚本(推荐)

把API请求的等待逻辑放在自执行异步函数里,等数据完全加载后,再动态创建script标签加载后续依赖文件,从根源上确保依赖代码在数据就绪后执行。

修改后的script1.js代码

class GlobalConstants {
  constructor() {
    this.dynamicData = {};
  }

  async getConfigData() {
    try {
      const configResponse = await fetch("https://jsonplaceholder.typicode.com/todos/1");
      if (configResponse.status === 200) {
        const dummyData = await configResponse.json();
        this.dynamicData = dummyData; // 修正原代码的赋值错误
      } else {
        throw new Error(`Config API 返回状态码: ${configResponse.status}`);
      }
    } catch (error) {
      console.warn("获取配置失败:", error);
    }
  }
}

// 自执行异步函数:先初始化并等待数据加载,再加载依赖脚本
(async function() {
  window.globalConstants = new GlobalConstants();
  await globalConstants.getConfigData();
  
  // 按顺序加载后续依赖脚本
  const dependencyScripts = ["https://test.com/script2.js", "https://test.com/script3.js"];
  for (const src of dependencyScripts) {
    const scriptTag = document.createElement('script');
    scriptTag.src = src;
    scriptTag.async = false; // 保证脚本按顺序执行
    document.head.appendChild(scriptTag);
  }

  // 此时输出就能拿到正确数据
  console.log(globalConstants.dynamicData);
})();

修改后的HTML

只需要保留第一个脚本即可:

<!DOCTYPE HTML>
<html>
<head>
    <script src="https://test.com/script1.js"></script>
 </head>
<body>
 <div id="body"></div>
</body>
</html>

这个方案不需要修改依赖脚本的内容,完全通过控制脚本加载时机实现需求,不会阻塞页面主线程。


方案2:全局Promise+延迟执行依赖脚本

如果不想动态加载脚本,可以把数据加载的异步过程包装成一个全局Promise,让依赖脚本等待这个Promise完成。

修改后的script1.js代码

class GlobalConstants {
  constructor() {
    this.dynamicData = {};
    this.loadComplete = this.getConfigData(); // 把异步请求包装成Promise存入全局
  }

  async getConfigData() {
    try {
      const configResponse = await fetch("https://jsonplaceholder.typicode.com/todos/1");
      if (configResponse.status === 200) {
        const dummyData = await configResponse.json();
        this.dynamicData = dummyData;
      } else {
        throw new Error(`Config API 返回状态码: ${configResponse.status}`);
      }
    } catch (error) {
      console.warn("获取配置失败:", error);
    }
  }
}

window.globalConstants = new GlobalConstants();

修改后的HTML

给依赖脚本加上defer,确保它们在DOM加载完成后执行:

<!DOCTYPE HTML>
<html>
<head>
    <script src="https://test.com/script1.js"></script>
    <script src="https://test.com/script2.js" defer></script>
    <script src="https://test.com/script3.js" defer></script>
 </head>
<body>
 <div id="body"></div>
</body>
</html>

依赖脚本(如script2.js)的写法

在依赖脚本里等待全局Promise完成后再执行业务代码:

(async function() {
  await globalConstants.loadComplete;
  // 这里写依赖全局数据的代码
  console.log("script2拿到的全局数据:", globalConstants.dynamicData);
})();

这个方案需要修改所有依赖脚本,但不需要调整脚本引入的逻辑结构。


方案3:同步XHR(不推荐)

虽然可以用同步XMLHttpRequest实现同步请求,但会阻塞浏览器主线程,导致页面卡顿、用户体验极差,仅做知识补充,强烈不推荐在生产环境使用:

class GlobalConstants {
  constructor() {
    this.dynamicData = {};
    this.getConfigData();
  }

  getConfigData() {
    try {
      const xhr = new XMLHttpRequest();
      xhr.open('GET', "https://jsonplaceholder.typicode.com/todos/1", false); // 第三个参数false表示同步请求
      xhr.send();
      if (xhr.status === 200) {
        const dummyData = JSON.parse(xhr.responseText);
        this.dynamicData = dummyData;
      } else {
        throw new Error(`Config API 返回状态码: ${xhr.status}`);
      }
    } catch (error) {
      console.warn("获取配置失败:", error);
    }
  }
}

window.globalConstants = new GlobalConstants();
console.log(globalConstants.dynamicData); // 此时会输出正确数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:04:54