Ajax回调返回[object object]求助:循环内Ajax获取表格数据
解决循环中异步AJAX获取数据组装HTML的问题
兄弟,你遇到的核心问题就是AJAX的异步特性——你的同步循环代码会在AJAX请求完成前就执行,这时候getData()返回的根本不是你想要的td字符串,而是jQuery的AJAX请求对象(也就是你看到的[Object object]);而success回调里的结果要等服务器响应后才会生成,这时候你的循环早就跑完了,自然拿不到正确值。
问题拆解
$.ajax()本身返回的是jqXHR对象(实现了Promise接口),不是success回调里的返回值,直接把它加到html里肯定会显示对象。- 循环是同步执行的,而每个AJAX请求是异步完成的,你没法在循环里同步拿到回调里的结果——回调触发的时候,当前循环的迭代早就结束了。
- 你代码里用了
var i,这还会导致闭包问题:所有AJAX请求最终拿到的i都是循环的最后一个值,这也是隐藏的坑。
解决方案:用async/await处理异步请求
现在最直观的方式是用async/await让异步代码看起来像同步的,同时并行处理所有请求保证效率:
// 封装单个日期的请求与td生成逻辑 async function getDayTd(i) { try { // 用await等待AJAX请求完成,直接拿到返回数据 const data = await $.ajax({ url: "http://localhost:8888/vs-time-tracking-ajax-calendar/", data: { i: i }, type: "POST", dataType: "json" }); // 生成对应的td元素 let tdClass = "ic__day"; const targetDate = moment(timeNowLocal).date(data.i).format("D.M.YYYY"); if (targetDate === timeNow.format("D.M.YYYY")) { tdClass = "ic__day ic__day_state_current"; } else if (timeSelected && targetDate === timeSelected.format("D.M.YYYY")) { tdClass = "ic__day ic__day_state_selected"; } return `<td class="${tdClass}">${data.i}</td>`; } catch (error) { alert(error.responseText); // 出错时返回一个容错的td,避免影响整体结构 return `<td class="ic__day ic__day_state_error">Error</td>`; } } // 批量处理所有日期请求,组装最终HTML async function buildCalendarHtml() { let html = ""; // 收集所有请求的Promise对象 const tdPromises = []; // 用let i避免闭包问题 for (let i = 1; i <= monthLastDay; i++) { tdPromises.push(getDayTd(i)); } // 等待所有请求完成,一次性拿到所有生成好的td字符串 const tdElements = await Promise.all(tdPromises); // 拼接所有td html += tdElements.join(""); // 这里就可以用生成好的html做后续操作了,比如插入到DOM console.log(html); // 示例:$("#calendar-container").html(html); } // 调用函数生成日历HTML buildCalendarHtml();
为什么这样可行?
getDayTd是async函数,用await等待AJAX请求完成,拿到数据后直接生成td字符串并返回,这个函数本身会返回一个Promise。- 我们把所有日期的请求Promise收集到数组里,用
Promise.all并行等待所有请求完成,既能保证效率,又能一次性拿到所有结果。 - 所有异步操作完成后再拼接HTML,这时候你拿到的就是完整的、正确的表格单元格内容了。
兼容旧环境的替代方案:用jQuery Deferred
如果需要兼容不支持async/await的旧浏览器,可以用jQuery的Deferred对象处理:
function getDayTd(i) { const deferred = $.Deferred(); $.ajax({ url: "http://localhost:8888/vs-time-tracking-ajax-calendar/", data: { i: i }, type: "POST", dataType: "json", success: function(data) { let tdClass = "ic__day"; const targetDate = moment(timeNowLocal).date(data.i).format("D.M.YYYY"); if (targetDate === timeNow.format("D.M.YYYY")) { tdClass = "ic__day ic__day_state_current"; } else if (timeSelected && targetDate === timeSelected.format("D.M.YYYY")) { tdClass = "ic__day ic__day_state_selected"; } deferred.resolve(`<td class="${tdClass}">${data.i}</td>`); }, error: function(request) { alert(request.responseText); deferred.resolve(`<td class="ic__day ic__day_state_error">Error</td>`); } }); return deferred.promise(); } // 收集所有请求的Deferred对象 const promises = []; for (let i = 1; i <= monthLastDay; i++) { promises.push(getDayTd(i)); } // 等待所有请求完成后组装HTML $.when.apply($, promises).done(function() { let html = ""; // arguments中包含所有请求返回的td字符串 for (const td of arguments) { html += td; } // 处理最终生成的HTML console.log(html); });
关键注意点
- 尽量不要在循环里串行等待每个AJAX请求(比如把await放在循环内),这样会让请求逐个执行,效率极低;用
Promise.all并行发起请求是更优的选择。 - 一定要处理错误情况,避免某个请求失败导致整个页面逻辑崩溃。
- 循环里必须用
let i而不是var i,否则闭包会导致所有请求拿到的都是最后一个循环值。
内容的提问来源于stack exchange,提问作者John M
相关产品推荐
相关产品推荐

