JavaScript全局变量初始化问题求助
为什么我的
tempdata变量无法被初始化为"new data"? 别急,这不是变量提升的锅,问题出在AJAX请求的异步特性上,咱们一步步拆解清楚:
你的代码实际执行顺序是这样的:
- 初始化
tempdata = "tempdata variable" - 创建XMLHttpRequest实例,绑定
onload回调函数(这个函数此时只是被定义,完全没执行) - 调用
req.send()发送请求,浏览器开始在后台处理这个网络请求 - 立刻执行
console.log(tempdata)——这时候请求还在后台跑,onload里的代码根本没机会执行,所以输出的还是初始值 - 等网络请求完成后,浏览器才会触发
onload回调,这时候tempdata = "new data"才会执行,但这时候之前的console.log早就跑完了
怎么解决?
你需要把依赖tempdata的逻辑放到请求完成的回调里,或者用现代的异步方案(Promise/async/await)让代码“等待”请求完成。
方案1:把逻辑移到onload回调内
这是最简单的修改方式,确保在请求完成后再处理tempdata:
create(){ console.log("creating Menu"); console.log("requesting Menu from source:" + this._src); try{ if(document.getElementById("menu-placeholder") == null){ throw "MenuManager: Menu Placeholder not found. Please create an <div>-Element with id 'menu-placeholder' and an unique data-menu-id attribute to contain a menu. If the <div>-Element is created, then check if #<MenuManager>.create() is executed after DOMContent is loaded."; } } catch(error){ throw new Error(error); } let tempdata = "tempdata variable"; let req = new XMLHttpRequest(); req.onload = (event) => { tempdata = "new data"; console.log("MenuManager / " + this._src); console.log("inside function : " + tempdata); // 所有需要用到tempdata的代码都放到这里 console.log(tempdata); // 现在会输出"new data" } req.open( 'GET', this._src ); req.setRequestHeader("Accept","text/json"); req.send(); }
方案2:用Promise+async/await让代码更易读
如果你的代码逻辑比较复杂,回调嵌套会很麻烦,用Promise封装AJAX请求,再结合async/await让异步代码看起来像同步代码:
class MenuManager{ constructor(menuSource){ this._src = menuSource; this._menudata; } get src(){ return this._src; } get MenuData(){ return this._menudata; } set menudata(newdata){ this._menudata = newdata; console.dir("MenuData set to: " + JSON.stringify(this._menudata)); } // 封装AJAX请求为Promise(私有方法) #fetchMenuData() { return new Promise((resolve, reject) => { const req = new XMLHttpRequest(); req.onload = () => { if (req.status >= 200 && req.status < 300) { resolve(req.response); } else { reject(new Error(`请求失败,状态码:${req.status}`)); } }; req.onerror = () => reject(new Error("网络请求出错")); req.open('GET', this._src); req.setRequestHeader("Accept", "text/json"); req.send(); }); } // 把create改成async函数 async create(){ console.log("creating Menu"); console.log("requesting Menu from source:" + this._src); try{ if(document.getElementById("menu-placeholder") == null){ throw "MenuManager: Menu Placeholder not found. Please create an <div>-Element with id 'menu-placeholder' and an unique data-menu-id attribute to contain a menu. If the <div>-Element is created, then check if #<MenuManager>.create() is executed after DOMContent is loaded."; } let tempdata = "tempdata variable"; // 等待请求完成 await this.#fetchMenuData(); tempdata = "new data"; console.log(tempdata); // 这里会输出"new data" console.log("MenuManager / " + this._src); } catch(error){ throw new Error(error); } } }
总结一下
你遇到的问题和变量提升完全无关,核心是AJAX的异步特性:浏览器不会暂停代码执行等待请求完成,而是继续往下跑同步代码,等请求有结果了再回头执行回调。只要把依赖异步结果的逻辑放到回调里,或者用async/await等待请求完成,就能解决这个问题。
内容的提问来源于stack exchange,提问作者laim2003
相关产品推荐
相关产品推荐

