Ajax异步请求问题:遍历ID调用API时避免函数提前返回
解决异步Ajax请求导致返回结果不符合预期的问题
首先,咱们来拆解下你的代码为什么会出现预期外的结果:
getArrConcat: function (id) { var arr = new Array(); var arrJoin = ""; for (var i=0; i<id.length; i++){ Model.load(id[i], { success: function (org) { arr.push(org.data); } }); } arrJoin = arr.join('; '); return arrJoin; }
问题根源
Model.load是异步Ajax请求——浏览器会在后台发起请求,代码却会继续往下执行,完全不会等待请求完成。所以当你的代码走到arrJoin = arr.join('; ')和return arrJoin时,所有success回调都还没触发,arr还是个空数组,自然返回的结果不是你想要的。
下面给你几种实用的解决方案,从现代异步处理方式到兼容旧环境的方案都有:
方案1:使用Promise + async/await(推荐)
先把Model.load封装成返回Promise的函数,这样就能用async/await优雅地等待所有请求完成:
// 封装Model.load为Promise版本,同时处理成功和失败场景 function loadModel(id) { return new Promise((resolve, reject) => { Model.load(id, { success: (org) => resolve(org.data), error: (err) => reject(err) }); }); } // 改造你的getArrConcat方法 getArrConcat: async function (id) { // 用Promise.all等待所有请求完成,结果数组顺序和id数组一致 const dataArr = await Promise.all(id.map(itemId => loadModel(itemId))); return dataArr.join('; '); }
使用说明:
- 这个方法是异步函数,调用时需要用
await或者.then()获取结果,比如:// 用await的方式(需要在async函数内调用) const result = await getArrConcat(yourIdArray); console.log(result); // 或者用.then()链式调用 getArrConcat(yourIdArray).then(result => console.log(result));
方案2:传统回调函数(兼容旧环境)
如果你的项目环境不支持ES6+特性,可以用计数器跟踪请求完成状态:
getArrConcat: function (id, callback) { var arr = new Array(); var completedCount = 0; const totalRequests = id.length; for (var i=0; i<totalRequests; i++){ Model.load(id[i], { success: function (org) { arr.push(org.data); completedCount++; // 所有请求完成后,调用回调返回结果 if (completedCount === totalRequests) { callback(arr.join('; ')); } }, error: function() { // 错误处理:即使请求失败,也要保证计数器递增,避免永远不触发回调 completedCount++; if (completedCount === totalRequests) { callback(arr.join('; ')); } } }); } }
使用说明:
调用时传入回调函数获取结果:
getArrConcat(yourIdArray, function(result) { console.log(result); });
方案3:Promise.all链式调用(不用async/await)
如果能使用Promise但不想用async/await,可以直接用.then()处理结果:
function loadModel(id) { return new Promise((resolve, reject) => { Model.load(id, { success: (org) => resolve(org.data), error: (err) => reject(err) }); }); } getArrConcat: function (id) { return Promise.all(id.map(itemId => loadModel(itemId))) .then(dataArr => dataArr.join('; ')); }
使用说明:
调用方式和方案1的.then()写法一致:
getArrConcat(yourIdArray).then(result => console.log(result));
不管选哪种方案,核心思路都是等所有异步请求全部完成后,再处理结果并返回,而不是在请求还在后台跑的时候就执行return。
内容的提问来源于stack exchange,提问作者Cristina Moretti
相关产品推荐
相关产品推荐

