jQuery Ajax成功回调异步问题:异步模式下getJonSnow无法正常工作
解决异步Ajax导致内容无法正确拼接的问题
这个问题我太熟悉了——你遇到的核心矛盾就是异步操作的非阻塞特性。当你把getJonSnow设为异步时,each循环会继续往下跑,不会等异步请求返回结果;而当你执行$("#content").html(feature)的时候,那些依赖getJonSnow返回值的内容还没来得及被拼到feature里,自然就看不到效果。同步模式下,代码会阻塞等待请求完成,所以能正常拼接,但同步Ajax会卡死页面,绝对不是最佳实践。
下面给你两种靠谱的解决方案,都是用Promise来管理异步任务,既保证功能正常,又不影响用户体验:
方案一:用Promise.all批量处理异步请求
这种方法适合希望并行发起所有异步请求、提高效率的场景:
首先改造getJonSnow,让它返回一个Promise:
function getJonSnow(attributecode) { return new Promise((resolve) => { $.ajax({ url: "test_php.php?function=getvalues", cache: false, success: resolve }); }); }
然后修改handleHousestark函数,把同步内容和异步任务分开收集,等所有异步请求完成后再合并内容:
function handleHousestark(html) { const xmlDoc = $.parseXML(html); const $xml = $(xmlDoc); const featureParts = []; // 存储同步生成的内容片段 const asyncTasks = []; // 存储异步Promise任务 $xml.find("features").children().each(function() { const attributevalue = $(this).attr('value'); const attributeunittype = $(this).attr('type'); const attributecode = $(this).attr('code'); if (attributeunittype !== "Valuelist") { // 同步内容直接加入数组 featureParts.push(`<B>${attributevalue}</B><BR/>`); } else { // 把异步请求包装成Promise,加入任务数组 asyncTasks.push( getJonSnow(attributecode).then(res => { return `<B>${res}</B><BR/>`; }) ); } }); // 等所有异步任务完成后,合并所有内容并更新DOM Promise.all(asyncTasks).then(asyncParts => { const finalFeature = featureParts.join('') + asyncParts.join(''); $("#content").html(finalFeature); }); }
方案二:用async/await实现“类同步”的异步代码
如果你习惯同步代码的写法,可以用async/await让异步逻辑看起来更直观:
同样先改造getJonSnow返回Promise:
function getJonSnow(attributecode) { return new Promise((resolve) => { $.ajax({ url: "test_php.php?function=getvalues", cache: false, success: resolve }); }); }
然后把handleHousestark改成async函数,注意这里要改用for...of遍历(jQuery的each不支持await):
async function handleHousestark(html) { const xmlDoc = $.parseXML(html); const $xml = $(xmlDoc); let feature = ""; // 把jQuery对象转成可遍历的数组,用for...of循环 const featureChildren = Array.from($xml.find("features").children()); for (const elem of featureChildren) { const $elem = $(elem); const attributevalue = $elem.attr('value'); const attributeunittype = $elem.attr('type'); const attributecode = $elem.attr('code'); if (attributeunittype !== "Valuelist") { feature += `<B>${attributevalue}</B><BR/>`; } else { // 等待异步请求返回结果后再继续 const res = await getJonSnow(attributecode); feature += `<B>${res}</B><BR/>`; } } // 所有内容拼接完成后再更新DOM $("#content").html(feature); }
这两种方案都能解决你的问题,而且避免了同步Ajax的阻塞问题。推荐优先用方案一,因为并行请求比串行请求更快;如果业务逻辑需要按顺序处理每个元素,方案二更合适。
内容的提问来源于stack exchange,提问作者user3780864
相关产品推荐
相关产品推荐

