如何获取for循环内的async返回值并按栈结构存储用于DOM渲染
实现方案
核心逻辑分三步:初始化栈结构、循环接收响应推入栈、全部请求完成后基于栈内容渲染DOM
具体实现
- 栈结构不需要额外造轮子,JavaScript原生数组已经实现了栈的核心方法(
push入栈、pop出栈、通过索引按顺序访问栈元素),直接用数组模拟即可 - 所有包含
await的逻辑必须放在async函数作用域内,否则会触发语法报错 - 每次接口返回响应后直接调用数组的
push方法把响应追加到栈顶即可,等整个循环执行完毕,栈就会存下所有接口的返回结果 - 等栈存储完成后,把栈作为参数传入DOM渲染函数,即可完成页面输出
可直接运行的完整代码
// 初始化空栈,存储所有接口返回的响应 const shippingResStack = []; async function runShippingRequest() { // 循环变量用let声明为块级作用域,避免意外污染全局 for (let i = 1; i <= 2; i++) { const response = await shippingService.createShippingAddress(request); // 响应推入栈顶 shippingResStack.push(response); console.log(`第${i}次请求完成,当前栈内元素数量:${shippingResStack.length}`); } // 所有请求执行完毕、栈填充完成,触发DOM渲染 renderToPage(shippingResStack); } /** * 基于栈结构渲染页面DOM * @param {Array} stack 存满接口响应的栈结构 */ function renderToPage(stack) { const listContainer = document.querySelector('#shipping-address-list'); // 清空容器原有内容 listContainer.innerHTML = ''; // 栈是后进先出特性,如果需要按入栈的反向顺序展示,从数组最后一位往前遍历即可 for (let idx = stack.length - 1; idx >= 0; idx--) { const addressInfo = stack[idx]; const addressNode = document.createElement('div'); addressNode.className = 'address-item'; addressNode.innerText = `${addressInfo.receiverName}:${addressInfo.detailAddress}`; listContainer.appendChild(addressNode); } } // 启动整个流程 runShippingRequest();
优化提示
如果不需要严格按顺序串行等待每个接口返回、想要提升整体请求效率,可以把所有请求Promise先收集起来,等全部完成后批量推入栈,示例片段:
async function runParallelRequest() { // 批量生成2个请求的Promise const requestList = Array.from({ length: 2 }, () => shippingService.createShippingAddress(request)); // 等所有请求返回结果 const resList = await Promise.all(requestList); // 批量把结果推入栈 shippingResStack.push(...resList); // 触发渲染 renderToPage(shippingResStack); }这种并行请求的总耗时约等于单个接口的请求时长,比串行等待的总耗时(两个接口时长之和)要低很多。
常见踩坑点
- 不要在全局作用域直接写顶层
await,部分旧浏览器/旧版本Node环境会不兼容,最好放到明确声明的async函数里 - 循环变量一定要用
let声明,如果用var或者不写声明,会导致循环变量全局共享,容易出现异步回调里拿到错误循环值的问题 - 如果渲染时不需要严格的后进先出栈特性,只是想统一收集所有结果再处理,直接用数组存储完全满足需求,不用额外封装栈类
内容的提问来源于stack exchange,提问作者xxxxxxxxxxxxxxoxx
相关产品推荐
相关产品推荐

