Promise提前resolve返回缺失Ajax数据,如何等待异步请求完成后返回完整数组
问题根因
- Promise的
resolve方法一旦调用就会终结当前Promise的状态,你原有代码里每处理完1个带variant参数的URL,或者1个Ajax请求成功后,就直接调用resolve(obj),导致第一个任务完成就提前返回,根本不会等待其他异步请求结束。 - 循环里的异步任务没有做统一的等待管理,无法感知所有任务的完成时机。
- 原有Ajax的error回调、参数校验逻辑中直接throw的错误无法被外层Promise的catch捕获,会直接抛出为全局异常。
修复方案
核心思路是把每个URL的处理逻辑都封装为独立Promise,同步的直接resolve结果,异步的Ajax请求在success回调里resolve结果,最后用Promise.all等待所有任务完成后统一返回结果数组,天然保证结果顺序和输入URL顺序一致。
function getProducts(product_links, product_quantity, trigger_word){ // 提前做全局参数合法性校验,不合法直接返回reject状态的Promise if(trigger_word == ''){ return Promise.reject(new Error("Something went wrong, please check trigger word enterd field!")); } if(!(product_links.length > 0 && product_quantity.length > 0 && product_links.length == product_quantity.length)){ return Promise.reject(new Error("Something went wrong, please check all product link fields and their quantity!")); } // 存储每个URL对应的处理Promise const taskList = []; for (let i = 0; i < product_links.length; i++){ const linkVal = $(product_links[i]).val(); const quantityVal = $(product_quantity[i]).val(); // 单条数据校验不合法直接reject整个任务 if(linkVal == '' || quantityVal == '' || !isUrl(linkVal) || !$.isNumeric(quantityVal) || quantityVal <= 0){ return Promise.reject(new Error("Something went wrong, please check all product link fields and their quantity!")); } const url = new URL(linkVal); const search_params = url.searchParams; // 每个处理逻辑包装成Promise推入任务列表 if(search_params.has("variant")){ // 带variant参数的同步逻辑,直接resolve结果 const res = { id: parseInt(search_params.get("variant")), quantity: parseInt(quantityVal) }; taskList.push(Promise.resolve(res)); console.log("Product with variant: ", res); }else{ // 无参数的异步Ajax逻辑,封装成Promise推入 taskList.push(new Promise((resolve, reject) => { const product_json = `${linkVal}.json`; $.ajax({ crossDomain: true, type: "GET", contentType: "application/json; charset=utf-8", url: product_json, dataType: "jsonp", headers:{ "Access-Control-Allow-Origin": "*" }, success: function(res){ const first_variant_id = res['product']['variants'][0]['id']; const product_name = res['product']['title']; const quantity_value = parseInt(quantityVal); const result = { id: first_variant_id, quantity: quantity_value }; console.log("Product name: ", product_name , "Product id: ", first_variant_id, "Quantity: ", quantity_value); resolve(result); }, error:function(err) { reject(new Error("Something went wrong, please check your internet connection and try again later!")); } }); })); } } // 等待所有任务完成后返回所有结果组成的数组 return Promise.all(taskList); } // 原有调用逻辑无需改动 getProducts(product_links, product_quantity, trigger_word) .then(function (products) { console.log(products); console.log(products.length); products.forEach(function(variant){ console.log(variant); }); }) .catch(function (err){ console.log(err); });
内容的提问来源于stack exchange,提问作者Stefan Momcilovic
相关产品推荐
相关产品推荐

