JS全局变量cleanup返回undefined 异步调用问题排查
问题背景
调试网页端脚本过程中,其余功能均已验证可用,目前遇到全局变量始终返回undefined的问题,无法判定是变量跨作用域传递失败,还是异步执行时序问题导致,暂不清楚时序问题的修复方案。
原始代码
function csvConvert(data) { //Data is usable here console.table(data); results = data.map(element => ({id: element.id})) string = JSON.stringify(results); window.cleanup = string.replace(/[&\/\\#+()$~%.'":*?<>{}]/g, '').replace(/id/g, '').replace(/null/g, '').slice(0, -2).substring(1); // the variable i need to use later outside the function console.log(cleanup); return cleanup; } function parseData(url, callBack) { Papa.parse(url, { header: true, download: true, dynamicTyping: true, complete: function(results) { callBack(results.data); } }); } const csvfile = document.getElementById('platform').innerHTML; // use element Id to choose file parseData("/csv/"+ csvfile + ".csv", csvConvert); test = "1627,2485,1075,3889,3810,23695,7862,1631,4156,9890" final = `fields name,summary,cover.image_id; where id = (` + csvConvert.cleanup + `); limit 50; sort first_release_date;`; //csvConvert.cleanup coming back as undefined console.log(final); xhr = new XMLHttpRequest(); xhr.onload = success; // call success function if request is successful xhr.open("POST", "https://foo.execute-api.us-west-2.amazonaws.com/production/v4/games/"); xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader("Content-Type", "application/json"); xhr.setRequestHeader("x-api-key", "foo"); xhr.send(final); // send the request to the server. console.log(this.responseText); function success () { if (xhr.readyState == 4) { if (xhr.status === 200) { const platform = document.getElementById('platform').innerHTML; var json = JSON.parse(xhr.responseText); //parse the string to JSON // FETCHING DATA FROM JSON FILE var tr; // build the table for (var i = 0; i < json.length; i++) { tr = $('<tr/>'); tr.append("<td>" + '<div class="image">' + '<img src = "https://images.igdb.com/igdb/image/upload/t_cover_big/' + json[i].cover.image_id + ".png" + '"></img>' + "</div>" + "</td>"); tr.append("<td>" + '<div class="name">' + json[i].name + "</div>" + '<div class="summary">' + json[i].summary + "</div>" + "</td>"); $('table').append(tr); }}}};
原有代码逻辑
- 通过PapaParse下载解析指定路径的CSV文件
- 在
csvConvert回调中处理解析数据,清洗后赋值给全局变量window.cleanup - 后续拼接
cleanup的值构造API查询语句,通过XHR发送POST请求拉取游戏数据 - 请求成功后解析返回的JSON,动态渲染包含游戏封面、名称、简介的表格
问题现象
访问csvConvert.cleanup取值时始终返回undefined;使用硬编码的test测试变量替换该位置时,后续XHR请求、表格渲染逻辑均可正常运行,仅cleanup变量无法正确获取处理后的值。
问题根因
- 取值路径错误:代码把清洗后的值挂载到了
window.cleanup上,而非csvConvert函数的属性上,csvConvert.cleanup本身就不存在。 - 核心为异步时序问题:
Papa.parse下载、解析CSV是异步操作,调用parseData后,主线程代码不会等待CSV解析完成、csvConvert回调执行完毕,就会直接向下执行拼接查询语句、发送XHR请求的逻辑。此时csvConvert还未触发执行,window.cleanup尚未被赋值,自然拿到undefined。
修复方案
不要依赖全局变量跨异步流程传值,把所有需要用到cleanup结果的逻辑,全部放到csvConvert回调内部执行,确保拿到清洗后的数据再拼接查询语句、发送请求。
修复后核心代码如下:
function csvConvert(data) { console.table(data); const results = data.map(element => ({id: element.id})) const string = JSON.stringify(results); const cleanup = string.replace(/[&\/\\#+()$~%.'":*?<>{}]/g, '').replace(/id/g, '').replace(/null/g, '').slice(0, -2).substring(1); console.log(cleanup); // 拿到cleanup后再构造查询语句、发请求 const final = `fields name,summary,cover.image_id; where id = (${cleanup}); limit 50; sort first_release_date;`; console.log(final); const xhr = new XMLHttpRequest(); xhr.onload = function() { if (xhr.readyState == 4 && xhr.status === 200) { const json = JSON.parse(xhr.responseText); let tr; for (let i = 0; i < json.length; i++) { tr = $('<tr/>'); tr.append(`<td> <div class="image"> <img src="https://images.igdb.com/igdb/image/upload/t_cover_big/${json[i].cover.image_id}.png"></img> </div> </td>`); tr.append(`<td> <div class="name">${json[i].name}</div> <div class="summary">${json[i].summary}</div> </td>`); $('table').append(tr); } } } xhr.open("POST", "https://foo.execute-api.us-west-2.amazonaws.com/production/v4/games/"); xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader("Content-Type", "application/json"); xhr.setRequestHeader("x-api-key", "foo"); xhr.send(final); } function parseData(url, callBack) { Papa.parse(url, { header: true, download: true, dynamicTyping: true, complete: function(results) { callBack(results.data); } }); } const csvfile = document.getElementById('platform').innerHTML; parseData(`/csv/${csvfile}.csv`, csvConvert);
额外优化:移除了不必要的全局变量声明,所有变量限定在对应作用域内,避免全局污染;去掉了无用的
test变量、回调外无意义的this.responseText打印(发送请求时响应还未返回,打印无意义)。
内容的提问来源于stack exchange,提问作者liam gore
相关产品推荐
相关产品推荐

