如何让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
相关产品推荐
相关产品推荐

